Skip to content
Snippets Groups Projects
Commit 00df0c29 authored by kr69sugu's avatar kr69sugu
Browse files

intial commit. see readme for details

parents
No related branches found
No related tags found
No related merge requests found
skyglow.log
moon?*
# skyglow
Python program written for the ecoLux project in the ecoTron to periodically set light-intensities of the LED's in the ecoUnits.
<ul>
<li>Parses a file containing the time and light intensities (mlx) for the moon</li>
<li>Converts the lightintensities to a DMX-Value (0-255)</li>
<li>Sets the moon-LED and 3-lightpollution LED's for each ecounit</li>
<li>logs the time and value</li>
</ul>
This was tested and run on a Raspberry Pi connected via DMX to the LED's in the ecounits.
OLA (Open Light Architecture Framework) is used to write to the DMX-Bus.
##Building OLA##
In order to get a recent version with python support we need to build OLA.
See [this](https://www.openlighting.org/ola/tutorials/ola-on-raspberry-pi/) and [this](https://www.openlighting.org/ola/linuxinstall/#Debian_Ubuntu) for details.
Install libraries (Python 2.x):
```console
sudo apt-get install libcppunit-dev libcppunit-1.15-0 uuid-dev pkg-config libncurses5-dev libtool autoconf automake g++ libmicrohttpd-dev libmicrohttpd12 protobuf-compiler libprotobuf-lite17 python-protobuf libprotobuf-dev libprotoc-dev zlib1g-dev bison flex make libftdi-dev libftdi1 libusb-1.0-0-dev liblo-dev libavahi-client-dev python-numpy
```
Clone repository:
```console
git clone https://github.com/OpenLightingProject/ola.git ola
cd ola
```
Configure for python:
```console
autoreconf -i
configure --enable-python-libs
```
Build
```console
make -j4 #run on 4 jobs (use nproc to check number cores)
make -j4 check
sudo make install
sudo ldconfig
```
Run the daemon:
```console
olad
```
##Usage##
It will look for a file called **moon** in its directory, to read the intensities of the moon.
```console
skyglow.py
```
Alternatively you can pass a different file as an argument.
```console
skyglow.py /path/to/moon/file
```
If you acquire a new moonfile, make sure to replace all occurrences of **24:00** to **00:00**.
Otherwise python will throw an error.
```console
sed -i 's/24:00/00:00/g' moonfile
```
If everything worked, a line should be added to skyglow.log:
```
#date moon[mlx] moon[dmx] lightpollution[mlx]
2020-07-21 15:00:00 0.05 11 [15, 54, 4, 19, 0, 1, 5, 0, 40, 12, 123, 123]
```
The indices of the list containing the lightpollution valus refer to the number of the ecounits.
Now set up a cronjob to check for new values every minute. Run
```
crontab -e
```
and insert
```
PATH=/usr/bin:/path/to/directory/containing/skyglow/
* * * * * skyglow.py
```
Check the `skyglow.log` to see if it gets updated every minute.
```
watch -n1 tail skyglow.log
```
\ No newline at end of file
moon 0 → 100644
This diff is collapsed.
#!/usr/bin/python2
from __future__ import print_function #python 2
import os
from ola.ClientWrapper import ClientWrapper
from datetime import datetime as dt
import array
import sys
# error / return codes
# # # # # # #
FAIL_DMX=3
FAIL_DMX_SEND=4
FAIL_LOG=5
FAIL_MOON=6
# either fullpath or just name (then logFile will be created in scriptdir)
# or fullpath containing '/'
logFile = "skyglow.log"
data = []
moonLux=0
moonDmx=0
#dmx setup
wrapper = None
UNIVERSE = 10
MAX_DMX_FRAME_SIZE = 512
#change according to needs
dmx_addr = [10,20,30,40,50,60,70,80,90,100,110,120]
# assert len(dmx_addr) == NUM_ECO_UNITS
# assert len(skyglow) == NUM_ECO_UNITS
#Mapping byte to lux
skyglow = [ 15, # one 0.08
54, # one 0.3
4, # all 1
19, # one 0.1
0, # none 0
1, # one 0.01
5, # one 0.03
0, # none 0
40, # all 10
12, # all 3
123, # all 30
123, # all 30
]
NUM_ECO_UNITS = len(skyglow)
sunrise = 0
sunset = 0
now = dt.now().replace(second=0, microsecond=0) # ignore seconds and microseconds
#mlx (idx is also dmx-byte value)
moon = [ 1.409,
8.369,
12.333,
16.210,
20.563,
24.716,
28.907,
33.363,
36.843,
41.137,
46.527,
50.880,
54.727,
59.617,
63.967,
67.817,
73.173,
77.213,
82.827,
87.037,
91.033,
95.320,
99.470,
104.366,
108.833,
113.667, #25
123.733,
128.567,
133.2,
138.3,
143.367,
148.233,
152.233,
156.933,
162.5,
167.5,
172.1,
176.767,
181.567,
187,
192.067,
196.433,
201.467, #42 > max-moon is 201.9mlx
206.5,
211.733,
216.4,
221.033,
226,
231.1,
235.733,
240.4, #50
]
#moonFile
DATE_COLUMN=0
TIME_COLUMN=1
MOON_COLUMN=13
IGNORE_FIRST_LINES=5
def moonlux2Byte(m):
'''find minimum Byte/Index in moonarray'''
m=m*1000
min_i = 0
min_m = max(moon)
min_dif = 999
for i in range(len(moon)):
if abs(m - moon[i]) < min_dif:
min_dif = abs(m - moon[i])
min_i = i
return min_i
def readLux():
''' read current lux-value file and transfer to byte-value '''
if not os.path.isfile(moonFile) or not os.access(moonFile, os.R_OK):
error(FAIL_MOON,"moonfile not accessable: " + moonFile)
with open(moonFile) as f:
lines = f.readlines()
del lines[0:IGNORE_FIRST_LINES] #remove no data lines
moonLux = float()
for line in lines:
line=line.split()
if len(line) < MOON_COLUMN+1:
continue
sdatetime = line[DATE_COLUMN] + " " + line[TIME_COLUMN]
parsed_datetime = dt.strptime(sdatetime,'%m-%d-%Y %H:%M')
# print(parsed_datetime)
if parsed_datetime == now:
moonLux = line[MOON_COLUMN]
print(str(now) + ": got moon illuminance of " + moonLux)
break;
return moonLux
def log(msg):
msg = str(now) + " " + msg + "\n"
if not os.access(logFile, os.X_OK) or os.access(logFile, os.W_OK):
print("writing log to file ", logFile)
with open(logFile, 'a') as f:
f.write(msg)
print(msg)
else:
print("Error! File: Can't write log to ",logFile)
exit(FAIL_LOG)
def error(exit_code, msg):
log("Error! " + str(msg))
exit(exit_code)
def addPathTo(filename):
cwd = os.path.realpath(__file__) # cwd = os.getcwd()
cwd = cwd[0:cwd.rindex('/')]
if '/' not in filename:
filename = cwd + "/" + filename
return filename
def init():
global logFile, moonFile, data
global sunrise, sunset, now
moonFile = 'moon'
if len(sys.argv) >= 2:
moonFile = sys.argv[1]
moonFile= addPathTo(moonFile)
logFile = addPathTo(logFile)
CHANNELS_PER_UNIT = 10 #4 used. 6reserved
USED_CHANNELS_PER_UNIT = 4
# data = array.array('B',[0]*130)
data = array.array('B',[0]*(((NUM_ECO_UNITS+1)*CHANNELS_PER_UNIT)-(NUM_ECO_UNITS*USED_CHANNELS_PER_UNIT))) # B=unsigned int
# timestring="09-09-2020 18:00"
# now = dt.strptime(timestring,'%m-%d-%Y %H:%M')
if( (now.month == 7) or (now.month == 8 and now.day <= 7 )):
sunrise = 6
sunset = 21
elif( now.month == 8 or (now.month == 9 and now.day <= 4 )):
sunrise = 7
sunset = 20
else:
sunrise = 7
sunset = 19
def isDay():
return ((now.hour >= sunrise) and (now.hour < sunset))
def dmxSent(status):
if not status.Succeeded():
error(FAIL_DMX_SEND,status.message)
global wrapper
if wrapper:
wrapper.Stop()
# only log after dmx status rcv
if isDay():
log('\t' + str(moonLux) + "\t" + str(moonDmx) + "\t[" + "0, "*(len(skyglow)-1) + "0]")
else:
log('\t' + str(moonLux) + "\t" + str(moonDmx) + "\t" + str(skyglow))
def main(args=""):
print("welcome to skyglow!")
print(args)
global data, moonLux, moonDmx
init()
moonLux = float(readLux())
moonDmx = moonlux2Byte(moonLux)
# print("moonDmx: ", moonDmx, "moonLux: ", moonLux)
for eco_unit in range(NUM_ECO_UNITS):
base = dmx_addr[eco_unit]
# print(now, sunrise, sunset)
if isDay():
pollution = 0
else:
pollution = skyglow[eco_unit]
print("unit:", eco_unit+1, " dmxaddr:", base," moon:", moonDmx, " pollution:", pollution)
if eco_unit in [2,8,9,10,11]:
data.insert(base-1, pollution)
data.insert(base, pollution)
data.insert(base+1, moonDmx)
data.insert(base+2, pollution)
else:
data.insert(base-1, pollution)
data.insert(base, 0)
data.insert(base+1, moonDmx)
data.insert(base+2, 0)
while( len(data) > MAX_DMX_FRAME_SIZE ):
print("Warning: cutting off data to fit DMX frame size of ", MAX_DMX_FRAME_SIZE)
data.pop()
print("DMX-Data:",data)
try:
global wrapper
wrapper = ClientWrapper()
client = wrapper.Client()
# send 1 dmx frame with values for channels 1-3 for all ecounits
client.SendDmx(UNIVERSE, data, dmxSent)
wrapper.Run()
except Exception as e:
error(FAIL_DMX,e)
if __name__ == '__main__':
main()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment