Compare commits

...

21 Commits

Author SHA1 Message Date
giuliof 0bc765b82e [python] Missing int conversion 2019-08-19 17:19:05 +02:00
giuliof 61978782c1 [python] better decoding 2019-08-19 17:15:13 +02:00
giulio bd38031a5f [python BE] Check for JSON labels 2019-08-17 11:45:30 +02:00
giulio 97259f47af [python BE] JSON labels 2019-08-17 11:38:54 +02:00
giulio 82dcc0d0cf [python BE] Missed value 2019-08-17 11:30:00 +02:00
giulio d9b1b49890 [python BE] Clima cfg file 2019-08-17 11:28:25 +02:00
giulio 5e99e11256 [python BE] Clima cfg file read/write 2019-08-17 11:28:18 +02:00
giulio e27b85db92 [python BE] permission on web scripts 2019-08-17 11:14:57 +02:00
giulio d3961b9ae3 [python BE] typo 2019-08-17 11:13:05 +02:00
giulio 4f57713964 [python BE] typo 2019-08-17 11:07:34 +02:00
giulio 31fc484dc5 [python BE] typo 2019-08-17 11:01:44 +02:00
giulio 24e7be2e27 [python BE] setClima and getAmbient 2019-08-17 11:01:07 +02:00
giulio 59486d8632 [python BE] moved DomoticGateway.py to web 2019-08-17 10:49:07 +02:00
giulio ee917094c1 [python BE] low level interface functions 2019-08-17 10:48:19 +02:00
giulio 17544992fc [python BE] low level interface prototypes 2019-08-17 10:17:10 +02:00
giulio 6adf02b3d6 [python BE] Full skel 2019-08-17 00:32:11 +02:00
giulio c895436336 [docs] ToDo 2019-08-17 00:22:52 +02:00
giulio 6bf508e7b5 [python] webserver folder 2019-08-17 00:22:52 +02:00
giuliof c8a407e483 [python] Scripts moved in its folder 2019-08-17 00:22:52 +02:00
giulio e918ceee74 [python BE] BackEnd dispatcher skel 2019-08-17 00:22:46 +02:00
giulio 0376a56f05 [docs] Testing caveat 2019-08-17 00:21:06 +02:00
6 changed files with 189 additions and 3 deletions

View File

@ -1,3 +1,13 @@
# domotic-gateway
A firmware interface for Arduino™ (but easily portable) for domotic application.
A firmware interface for Arduino™ (but easily portable) for domotic application.
**WARNING** - Testing branch, do not use for daily appications.
This branch will be destroyed once merged with main
## Possible stucture
- `web` folder should be linked to webserver document root directory (*TODO* .htaccess).
- `dispatcher.py` will accept web requests (*TODO* .htpasswd or other authorization methods).
- `scripts` will contain code for the automation (invoked by cron), like:
- `log-temperatures.py` to push local ambient paramenters and server statistics into database, then plot the data;
- `autoclima.py` to turn on the clima if necessary (*missing*).

79
python/DomoticGateway.py → web/DomoticGateway.py Executable file → Normal file
View File

@ -55,11 +55,11 @@ def temperature_conversion(raw):
class DomoticGateway:
def __init__(self):
def __init__(self, port = "/dev/ttyUSB0"):
for i in range(0, 3):
try:
self.ser = serial.Serial(
"/dev/ttyUSB0", 115200, timeout=0.5, exclusive=True)
port, 115200, timeout=0.5, exclusive=True)
sleep(0.1)
except:
sleep(1)
@ -108,3 +108,78 @@ class DomoticGateway:
return temperature_conversion(payload)
else:
raise ValueError('Invalid command')
# Populate this
# Arguments: mode, temperature, fan speed
# Convert to hex code, make packet and send it
def setClima(self, mode, temperature, fan):
# Code conversion (alpha, incomplete)
CLIMA_HEADER = 0x4d0000
CLIMA_MODES = {
'caldo' : 0b0011,
'freddo' : 0b1111,
'ventilatore' : 0b1011,
'deumidificatore' : 0b0100,
'auto' : 0b1000,
}
# [0] element is 24°C.
BASE_TMP = 24
CLIMA_TEMPERATURES = (0b1011, 0b0011, 0b0010, 0b0110, 0b0111)
FAN_SPEED = (0b0100, 0b0110, 0b1010, 0b1100)
# Static header
status = CLIMA_HEADER
if mode == 'spento':
status |= 0x841f
else:
# Mode (hot, cold, fan only, dehumidifier, auto)
try:
status |= CLIMA_MODES[mode]
except:
# NO! throw exception
print ("Invalid clima option")
exit(-1)
# Fan mode (not yet implemented)
# Temperature ()
try:
status |= CLIMA_TEMPERATURES[int(temperature) - BASE_TMP] << 4
except:
# NO! throw exception
print ("Invalid clima option")
exit(-1)
# No fan speed settings for these modes
if mode == 'auto' or mode == 'dehum':
status |= 0x00e000
else:
# Fan speed ()
try:
status |= FAN_SPEED[int(fan)] << 12
except:
# NO! throw exception
print ("Invalid clima option")
exit(-1)
# Clima packet is 4 bytes (uint32_t)
payload = []
payload.append(status & 0xff)
status >>= 8
payload.append(status & 0xff)
status >>= 8
payload.append(status & 0xff)
payload.append(0x00)
self.sendCommand('CMD_CLIMA', payload)
# Make ambient packet, wait for response, convert values and return
def getAmbient(self):
self.sendCommand('CMD_TEMP')
try:
tmp = self.receiveData()
except Exception as e:
tmp = None
return dict(zip(('ambtmp',), [tmp]))

5
web/conf/clima.ini Normal file
View File

@ -0,0 +1,5 @@
[clima]
mode =
temperature =
fan =

96
web/dispatcher.py Executable file
View File

@ -0,0 +1,96 @@
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
# GET me using a web browser,
# executing my code with a Python interpreter called by a CGI-compliant webserver!
# Example URI:
# http://www.example.org/path/dispatcher.py
import json
import cgitb, cgi
import configparser
import DomoticGateway as dg
# create a standard error JSON packet
def error(msg):
return {'ret' : 'error', 'msg' : msg}
# Read configuration files (latest files in list override previous settings)
cfg = configparser.ConfigParser()
# Start CGI handling for webserver
cgitb.enable()
inputvars = cgi.FieldStorage()
print('Content-Type: text/json; charset=utf-8')
print('Access-Control-Allow-Origin: *')
print()
### End of HTTP headers: it is now safe to output things
##########################################################
result = {'ret' : 'ok'}
if 'payload' not in inputvars:
result = error('No command provided')
else:
try:
payload = json.loads(inputvars['payload'].value)
except:
result = error('JSON payload is invalid')
# Send a message to clima unit
if payload['cmd'] == 'setClima':
if 'clima' not in payload:
result = error("Missing clima parameters")
else:
opts = payload['clima']
if not set(('mode', 'temperature', 'fan')).issubset(opts):
result = error("Invalid clima options")
else:
# buìld appropriate package and send
dgh = dg.DomoticGateway()
try:
dgh.setClima(**opts)
except TypeError:
result = error("Wrong parameter formatting")
except:
result = error("setClima error")
# Get last default options for clima
elif payload['cmd'] == 'getClima':
cfg.read(['conf/clima.ini', 'conf/clima.custom.ini'])
if 'clima' in cfg:
result = {**result, 'clima' : dict(cfg['clima'].items())}
else:
result = error("Malformed clima CFG file")
# Set default options for clima
elif payload['cmd'] == 'putClima':
if 'clima' not in payload:
result = error("Missing clima parameters")
else:
opts = payload['clima']
if not set(('mode', 'temperature', 'fan')).issubset(opts):
result = error("Invalid clima options")
else:
cfg['clima'] = opts
with open('conf/clima.custom.ini', 'w') as configfile:
cfg.write(configfile)
# Get ambient parameters
elif payload['cmd'] == 'getAmbient':
dgh = dg.DomoticGateway()
result = {**result, **dgh.getAmbient()}
else:
result = error('Invalid command provided')
print(json.dumps(result, indent=4))