Better timing tolerance
Add weather sensors wh2, wh7000 some python3 issues fix docu & PC PIR
This commit is contained in:
parent
3e70559ef2
commit
01ddd7e3cc
12 changed files with 476 additions and 393 deletions
|
@ -30,7 +30,7 @@ rfm.set_params(
|
|||
|
||||
## connair.py
|
||||
emulate a gateway for controlling RC sockets via the app power-switch. Compatible to "Brennenstuhl Brematic", Intertechno "ITGW-433", "ConnAir"
|
||||
see https://power-switch.eu/
|
||||
Here you find a python client controlling this gateway: https://github.com/markusressel/raspyrfm-client
|
||||
|
||||
## emoncms.py
|
||||
receive lacrosse-sensors with the RaspyRFM and post them to the open energy monitor, see https://openenergymonitor.org/
|
||||
|
@ -67,3 +67,8 @@ La crosse {'batlo': False, 'AFC': 376, 'init': False, 'T': (19.7, 'C'), 'RSSI':
|
|||
|
||||
## Product
|
||||
[Module RaspbyRFM Seegel Systeme](http://www.seegel-systeme.de/produkt/raspyrfm-ii/)
|
||||
|
||||
## Blog articles
|
||||
* [Software installation & examples (german)](http://www.seegel-systeme.de/2015/09/02/ein-funkmodul-fuer-den-raspberry-raspyrfm/)
|
||||
* [Control RC switches with RaspyRFM (german)](https://www.seegel-systeme.de/2015/09/05/funksteckdosen-mit-dem-raspberry-pi-steuern/)
|
||||
* [Receive lacrosse sensors (german)](http://www.seegel-systeme.de/2015/02/07/funkthermometer/)
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python2.7
|
||||
#!/usr/bin/env python
|
||||
|
||||
import socket
|
||||
from raspyrfm import *
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python2.7
|
||||
#!/usr/bin/env python
|
||||
|
||||
from raspyrfm import *
|
||||
import sys
|
||||
|
@ -113,7 +113,7 @@ def calcword(datain):
|
|||
result |= d
|
||||
return result
|
||||
|
||||
print "Waiting for sensors..."
|
||||
print("Waiting for sensors...")
|
||||
while 1:
|
||||
data = rfm.receive(56)
|
||||
data = descramble(data[0])
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python2.7
|
||||
#!/usr/bin/env python
|
||||
|
||||
from raspyrfm import *
|
||||
import sensors
|
||||
|
@ -7,7 +7,6 @@ import time
|
|||
import requests
|
||||
import json
|
||||
|
||||
|
||||
URL = 'https://emoncms.org/input/post.json'
|
||||
APIKEY = '123456789123456789'
|
||||
|
||||
|
@ -44,7 +43,7 @@ def LogSensor(data):
|
|||
if s['sensorId'] == data['ID']:
|
||||
if data['ID'] in lasttimes:
|
||||
if time.time() - lasttimes[data['ID']] < s['minInterval']:
|
||||
print "discarded value"
|
||||
print("discarded value")
|
||||
return
|
||||
lasttimes[data['ID']] = time.time()
|
||||
|
||||
|
@ -55,9 +54,9 @@ def LogSensor(data):
|
|||
|
||||
payload = {'apikey': APIKEY, 'node': s['node'], 'json': json.dumps(values)}
|
||||
r = requests.get(URL, params = payload)
|
||||
print "Sending to emon:", payload, "Result:", r
|
||||
print("Sending to emon:", payload, "Result:", r)
|
||||
return
|
||||
print "No match for ID"
|
||||
print("No match for ID")
|
||||
|
||||
|
||||
if raspyrfm_test(2, RFM69):
|
||||
|
@ -65,7 +64,7 @@ if raspyrfm_test(2, RFM69):
|
|||
elif raspyrfm_test(1, RFM69):
|
||||
rfm = RaspyRFM(1, RFM69) #when using a single single 868 MHz RaspyRFM
|
||||
else:
|
||||
print "No RFM69 module found!"
|
||||
print("No RFM69 module found!")
|
||||
exit()
|
||||
|
||||
rfm.set_params(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python2.7
|
||||
#!/usr/bin/env python
|
||||
|
||||
from raspyrfm import *
|
||||
import sensors
|
||||
|
@ -12,7 +12,7 @@ if raspyrfm_test(2, RFM69):
|
|||
rfm = RaspyRFM(2, RFM69) #when using the RaspyRFM twin
|
||||
elif raspyrfm_test(1, RFM69):
|
||||
print("Found RaspyRFM single")
|
||||
rfm = RaspyRFM(1, RFM69) #when using a single single 868 MHz RaspyRFM
|
||||
rfm = RaspyRFM(1, RFM69) #when using a single 868 MHz RaspyRFM
|
||||
else:
|
||||
print("No RFM69 module found!")
|
||||
exit()
|
||||
|
|
|
@ -1,229 +1,231 @@
|
|||
#!/usr/bin/env python2.7
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from raspyrfm import *
|
||||
import raspyrfm
|
||||
import sensors
|
||||
from sensors import rawsensor
|
||||
import sys
|
||||
import time
|
||||
import threading
|
||||
import math
|
||||
import json
|
||||
from datetime import datetime
|
||||
#import os
|
||||
import SocketServer
|
||||
import SimpleHTTPServer
|
||||
import urlparse
|
||||
|
||||
try:
|
||||
#python2.7
|
||||
import SocketServer as socketserver
|
||||
from urlparse import urlparse, parse_qs
|
||||
from SimpleHTTPServer import SimpleHTTPRequestHandler as Handler
|
||||
except ImportError:
|
||||
#python3
|
||||
import socketserver
|
||||
from http.server import SimpleHTTPRequestHandler as Handler
|
||||
from urllib.parse import urlparse, parse_qs
|
||||
|
||||
|
||||
lock = threading.Lock()
|
||||
|
||||
with open("lacrossegw.conf") as jfile:
|
||||
config = json.load(jfile)
|
||||
config = json.load(jfile)
|
||||
|
||||
if raspyrfm_test(2, RFM69):
|
||||
print("Found RaspyRFM twin")
|
||||
rfm = RaspyRFM(2, RFM69) #when using the RaspyRFM twin
|
||||
elif raspyrfm_test(1, RFM69):
|
||||
print("Found RaspyRFM single")
|
||||
rfm = RaspyRFM(1, RFM69) #when using a single single 868 MHz RaspyRFM
|
||||
if raspyrfm.raspyrfm_test(2, raspyrfm.RFM69):
|
||||
print("Found RaspyRFM twin")
|
||||
rfm = raspyrfm.RaspyRFM(2, raspyrfm.RFM69) #when using the RaspyRFM twin
|
||||
elif raspyrfm.raspyrfm_test(1, raspyrfm.RFM69):
|
||||
print("Found RaspyRFM single")
|
||||
rfm = raspyrfm.RaspyRFM(1, raspyrfm.RFM69) #when using a single single 868 MHz RaspyRFM
|
||||
else:
|
||||
print("No RFM69 module found!")
|
||||
exit()
|
||||
print("No RFM69 module found!")
|
||||
exit()
|
||||
|
||||
try:
|
||||
from influxdb import InfluxDBClient
|
||||
influxClient = InfluxDBClient(
|
||||
host=config["influxdb"]["host"],
|
||||
port=config["influxdb"]["port"],
|
||||
username=config["influxdb"]["user"],
|
||||
password=config["influxdb"]["pass"]
|
||||
)
|
||||
from influxdb import InfluxDBClient
|
||||
influxClient = InfluxDBClient(
|
||||
host=config["influxdb"]["host"],
|
||||
port=config["influxdb"]["port"],
|
||||
username=config["influxdb"]["user"],
|
||||
password=config["influxdb"]["pass"]
|
||||
)
|
||||
|
||||
createDb = True
|
||||
for db in influxClient.get_list_database():
|
||||
if db["name"] == config["influxdb"]["database"]:
|
||||
createDb = False
|
||||
break
|
||||
if createDb:
|
||||
influxClient.create_database(config["influxdb"]["database"])
|
||||
influxClient.switch_database(config["influxdb"]["database"])
|
||||
influxClient.alter_retention_policy("autogen", duration="2h", replication=1, shard_duration="1h")
|
||||
influxClient.create_retention_policy("one_week", duration="1w", replication=1, shard_duration='24h')
|
||||
influxClient.create_retention_policy("one_year", database=config["influxdb"]["database"], duration="365d", replication=1, shard_duration='1w')
|
||||
influxClient.create_continuous_query("three_min", 'SELECT mean(T) as "T", mean(RH) as "RH", mean(AH) as "AH", mean(DEW) as "DEW" INTO "one_week"."lacrosse" from "lacrosse" GROUP BY time(3m),*')
|
||||
influxClient.create_continuous_query("three_hour", 'SELECT mean(T) as "T", mean(RH) as "RH", mean(AH) as "AH", mean(DEW) as "DEW" INTO "one_week"."lacrosse" from "lacrosse" GROUP BY time(3h),*')
|
||||
else:
|
||||
influxClient.switch_database(config["influxdb"]["database"])
|
||||
createDb = True
|
||||
for db in influxClient.get_list_database():
|
||||
if db["name"] == config["influxdb"]["database"]:
|
||||
createDb = False
|
||||
break
|
||||
if createDb:
|
||||
influxClient.create_database(config["influxdb"]["database"])
|
||||
influxClient.switch_database(config["influxdb"]["database"])
|
||||
influxClient.alter_retention_policy("autogen", duration="2h", replication=1, shard_duration="1h")
|
||||
influxClient.create_retention_policy("one_week", duration="1w", replication=1, shard_duration='24h')
|
||||
influxClient.create_retention_policy("one_year", database=config["influxdb"]["database"], duration="365d", replication=1, shard_duration='1w')
|
||||
influxClient.create_continuous_query("three_min", 'SELECT mean(T) as "T", mean(RH) as "RH", mean(AH) as "AH", mean(DEW) as "DEW" INTO "one_week"."lacrosse" from "lacrosse" GROUP BY time(3m),*')
|
||||
influxClient.create_continuous_query("three_hour", 'SELECT mean(T) as "T", mean(RH) as "RH", mean(AH) as "AH", mean(DEW) as "DEW" INTO "one_week"."lacrosse" from "lacrosse" GROUP BY time(3h),*')
|
||||
else:
|
||||
influxClient.switch_database(config["influxdb"]["database"])
|
||||
|
||||
except Exception as ex:
|
||||
influxClient = None
|
||||
print("influx init error: " + ex.__class__.__name__ + " " + (''.join(ex.args)))
|
||||
influxClient = None
|
||||
print("influx init error: " + ex.__class__.__name__ + " " + (''.join(ex.args)))
|
||||
|
||||
try:
|
||||
import paho.mqtt.client as mqtt
|
||||
mqttClient = mqtt.Client()
|
||||
mqttClient.connect("localhost", 1883, 60)
|
||||
mqttClient.loop_start()
|
||||
import paho.mqtt.client as mqtt
|
||||
mqttClient = mqtt.Client()
|
||||
mqttClient.connect("localhost", 1883, 60)
|
||||
mqttClient.loop_start()
|
||||
except:
|
||||
mqttClient = None
|
||||
print("mqtt init error")
|
||||
mqttClient = None
|
||||
print("mqtt init error")
|
||||
|
||||
rfm.set_params(
|
||||
Freq = 868.300, #MHz center frequency
|
||||
Datarate = 9.579, #kbit/s baudrate
|
||||
ModulationType = rfm69.FSK, #modulation
|
||||
Deviation = 30, #kHz frequency deviation OBW = 69.6/77.2 kHz, h = 6.3/3.5
|
||||
ModulationType = raspyrfm.rfm69.FSK, #modulation
|
||||
SyncPattern = [0x2d, 0xd4], #syncword
|
||||
Bandwidth = 100, #kHz bandwidth
|
||||
#AfcBandwidth = 150,
|
||||
#AfcFei = 0x0E,
|
||||
RssiThresh = -100, #-100 dB RSSI threshold
|
||||
)
|
||||
|
||||
class BaudChanger(threading.Thread):
|
||||
baud = False
|
||||
def __init__(self):
|
||||
threading.Thread.__init__(self)
|
||||
baud = False
|
||||
def __init__(self):
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
time.sleep(15)
|
||||
print "Change baudrate"
|
||||
if self.baud:
|
||||
rfm.set_params(Datarate = 9.579)
|
||||
else:
|
||||
rfm.set_params(Datarate = 17.241)
|
||||
self.baud = not self.baud
|
||||
def run(self):
|
||||
while True:
|
||||
time.sleep(15)
|
||||
print("Change baudrate")
|
||||
if self.baud:
|
||||
rfm.set_params(Datarate = 9.579)
|
||||
else:
|
||||
rfm.set_params(Datarate = 17.241)
|
||||
self.baud = not self.baud
|
||||
|
||||
baudChanger = BaudChanger()
|
||||
baudChanger.daemon = True
|
||||
baudChanger.start()
|
||||
|
||||
def writeInflux(payload):
|
||||
if not influxClient:
|
||||
return
|
||||
T = payload["T"]
|
||||
wr = {
|
||||
"measurement": "lacrosse",
|
||||
"fields": {
|
||||
"T": T
|
||||
},
|
||||
"tags": {"sensor": payload["ID"] if not ("room" in payload) else payload["room"]}
|
||||
}
|
||||
if not influxClient:
|
||||
return
|
||||
T = payload["T"]
|
||||
wr = {
|
||||
"measurement": "lacrosse",
|
||||
"fields": {
|
||||
"T": T
|
||||
},
|
||||
"tags": {"sensor": payload["ID"] if not ("room" in payload) else payload["room"]}
|
||||
}
|
||||
|
||||
if ("RH" in payload):
|
||||
wr["fields"]["RH"] = payload['RH']
|
||||
wr["fields"]["DEW"] = payload["DEW"]
|
||||
wr["fields"]["AH"] = payload["AH"]
|
||||
if ("RH" in payload):
|
||||
wr["fields"]["RH"] = payload['RH']
|
||||
wr["fields"]["DEW"] = payload["DEW"]
|
||||
wr["fields"]["AH"] = payload["AH"]
|
||||
|
||||
influxClient.write_points([wr])
|
||||
influxClient.write_points([wr])
|
||||
|
||||
def getCacheSensor(id, sensorConfig = None):
|
||||
sensor = None
|
||||
if (id in cache) and ((datetime.now() - cache[id]["ts"]).total_seconds() < 180):
|
||||
sensor = cache[id]["payload"]
|
||||
if sensorConfig is not None:
|
||||
if ('tMax' in sensorConfig) and (sensor["T"] > sensorConfig["tMax"]):
|
||||
sensor["tStatus"] = "high"
|
||||
sensor = None
|
||||
if (id in cache) and ((datetime.now() - cache[id]["ts"]).total_seconds() < 180):
|
||||
sensor = cache[id]["payload"]
|
||||
if sensorConfig is not None:
|
||||
if ('tMax' in sensorConfig) and (sensor["T"] > sensorConfig["tMax"]):
|
||||
sensor["tStatus"] = "high"
|
||||
|
||||
if ('tMin' in sensorConfig) and (sensor["T"] < sensorConfig["tMin"]):
|
||||
sensor["tStatus"] = "low"
|
||||
if ('tMin' in sensorConfig) and (sensor["T"] < sensorConfig["tMin"]):
|
||||
sensor["tStatus"] = "low"
|
||||
|
||||
if ('tStatus' not in sensor) and ('tMax' in sensorConfig or 'tMin' in sensorConfig):
|
||||
sensor["tStatus"] = "ok"
|
||||
if ('tStatus' not in sensor) and ('tMax' in sensorConfig or 'tMin' in sensorConfig):
|
||||
sensor["tStatus"] = "ok"
|
||||
|
||||
if ('RH' in sensor):
|
||||
outSensor = getCacheSensor(sensorConfig["idOutside"]) if 'idOutside' in sensorConfig else None
|
||||
if (outSensor is not None) and ('AH' in outSensor):
|
||||
sensor["AHratio"] = round((outSensor["AH"] / sensor["AH"] - 1) * 100)
|
||||
sensor["RHvent"] = round(outSensor["DD"] / sensor["SDD"] * 100)
|
||||
if ('RH' in sensor):
|
||||
outSensor = getCacheSensor(sensorConfig["idOutside"]) if 'idOutside' in sensorConfig else None
|
||||
if (outSensor is not None) and ('AH' in outSensor):
|
||||
sensor["AHratio"] = round((outSensor["AH"] / sensor["AH"] - 1) * 100)
|
||||
sensor["RHvent"] = round(outSensor["DD"] / sensor["SDD"] * 100)
|
||||
|
||||
if ('rhMax' in sensorConfig) and (sensor["RH"] > sensorConfig["rhMax"]):
|
||||
#too wet!
|
||||
sensor["rhStatus"] = "high"
|
||||
if "AHratio" in sensor:
|
||||
if sensor["AHratio"] <= -10:
|
||||
sensor["window"] = "open"
|
||||
elif sensor["AHratio"] >= 10:
|
||||
sensor["window"] = "close"
|
||||
if ('rhMax' in sensorConfig) and (sensor["RH"] > sensorConfig["rhMax"]):
|
||||
#too wet!
|
||||
sensor["rhStatus"] = "high"
|
||||
if "AHratio" in sensor:
|
||||
if sensor["AHratio"] <= -10:
|
||||
sensor["window"] = "open"
|
||||
elif sensor["AHratio"] >= 10:
|
||||
sensor["window"] = "close"
|
||||
|
||||
if ('rhMin' in sensorConfig) and (sensor["RH"] < sensorConfig["rhMin"]):
|
||||
#too dry
|
||||
sensor["rhStatus"] = "low"
|
||||
if "AHratio" in sensor:
|
||||
if sensor["AHratio"] >= 10:
|
||||
sensor["window"] = "open"
|
||||
elif sensor["AHratio"] <= -10:
|
||||
sensor["window"] = "close"
|
||||
if ('rhMin' in sensorConfig) and (sensor["RH"] < sensorConfig["rhMin"]):
|
||||
#too dry
|
||||
sensor["rhStatus"] = "low"
|
||||
if "AHratio" in sensor:
|
||||
if sensor["AHratio"] >= 10:
|
||||
sensor["window"] = "open"
|
||||
elif sensor["AHratio"] <= -10:
|
||||
sensor["window"] = "close"
|
||||
|
||||
if 'rhStatus' not in sensor and ('rhMin' in sensorConfig or 'rhMax' in sensorConfig):
|
||||
sensor["rhStatus"] = "ok"
|
||||
if 'rhStatus' not in sensor and ('rhMin' in sensorConfig or 'rhMax' in sensorConfig):
|
||||
sensor["rhStatus"] = "ok"
|
||||
|
||||
return sensor
|
||||
return sensor
|
||||
|
||||
class MyHttpRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
def getjson(self):
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type', 'application/json')
|
||||
self.end_headers()
|
||||
resp = {"sensors": []}
|
||||
idlist = []
|
||||
|
||||
lock.acquire()
|
||||
for csens in config["sensors"]:
|
||||
id = csens["id"]
|
||||
sensor = getCacheSensor(id, csens)
|
||||
if sensor is not None:
|
||||
#print("Sensor: ", sensor)
|
||||
idlist.append(id)
|
||||
else:
|
||||
sensor = {}
|
||||
sensor["room"] = csens["name"]
|
||||
sensor["ID"] = id
|
||||
resp["sensors"].append(sensor)
|
||||
class MyHttpRequestHandler(Handler):
|
||||
def getjson(self):
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type', 'application/json')
|
||||
self.end_headers()
|
||||
resp = {"sensors": []}
|
||||
idlist = []
|
||||
|
||||
lock.acquire()
|
||||
for csens in config["sensors"]:
|
||||
id = csens["id"]
|
||||
sensor = getCacheSensor(id, csens)
|
||||
if sensor is not None:
|
||||
idlist.append(id)
|
||||
else:
|
||||
sensor = {}
|
||||
sensor["room"] = csens["name"]
|
||||
sensor["ID"] = id
|
||||
resp["sensors"].append(sensor)
|
||||
|
||||
for id in cache:
|
||||
if id in idlist:
|
||||
continue
|
||||
for id in cache:
|
||||
if id in idlist:
|
||||
continue
|
||||
|
||||
sensor = getCacheSensor(id)
|
||||
if sensor is not None:
|
||||
resp["sensors"].append(sensor)
|
||||
sensor = getCacheSensor(id)
|
||||
if sensor is not None:
|
||||
resp["sensors"].append(sensor)
|
||||
|
||||
lock.release()
|
||||
lock.release()
|
||||
|
||||
self.wfile.write(json.dumps(resp))
|
||||
|
||||
def do_GET(self):
|
||||
url = urlparse.urlparse(self.path)
|
||||
p = url.path
|
||||
q = urlparse.parse_qs(url.query)
|
||||
if 'name' in q:
|
||||
name = q['name'][0]
|
||||
self.wfile.write(json.dumps(resp).encode())
|
||||
|
||||
def do_GET(self):
|
||||
url = urlparse(self.path)
|
||||
p = url.path
|
||||
q = parse_qs(url.query)
|
||||
if 'name' in q:
|
||||
name = q['name'][0]
|
||||
|
||||
if p == '/data':
|
||||
self.getjson()
|
||||
if p == '/data':
|
||||
self.getjson()
|
||||
|
||||
elif p == '/':
|
||||
self.path = 'index.html'
|
||||
return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
|
||||
elif p == '/':
|
||||
self.path = 'index.html'
|
||||
return Handler.do_GET(self)
|
||||
|
||||
elif p == '/history' and influxClient and name:
|
||||
resp = influxClient.query(
|
||||
"SELECT mean(T), mean(RH) FROM one_week.lacrosse WHERE (sensor = $name) AND time >= now() - 4h GROUP BY time(3m) fill(none)",
|
||||
bind_params={'name': name}
|
||||
)
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type', 'application/json')
|
||||
self.end_headers()
|
||||
self.wfile.write(json.dumps(resp.raw['series'][0]['values']))
|
||||
|
||||
else:
|
||||
return self.send_error(404, self.responses.get(404)[0])
|
||||
elif p == '/history' and influxClient and name:
|
||||
resp = influxClient.query(
|
||||
"SELECT mean(T), mean(RH) FROM one_week.lacrosse WHERE (sensor = $name) AND time >= now() - 4h GROUP BY time(3m) fill(none)",
|
||||
bind_params={'name': name}
|
||||
)
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type', 'application/json')
|
||||
self.end_headers()
|
||||
self.wfile.write(json.dumps(resp.raw['series'][0]['values']).encode())
|
||||
else:
|
||||
return self.send_error(404, self.responses.get(404)[0])
|
||||
|
||||
|
||||
class Server(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
|
||||
pass
|
||||
class Server(socketserver.ThreadingMixIn, socketserver.TCPServer):
|
||||
pass
|
||||
|
||||
cache = {}
|
||||
|
||||
|
@ -232,94 +234,93 @@ server_thread = threading.Thread(target=server.serve_forever)
|
|||
server_thread.daemon = True
|
||||
server_thread.start()
|
||||
|
||||
print "Waiting for sensors..."
|
||||
print("Waiting for sensors...")
|
||||
|
||||
while 1:
|
||||
rxObj = rfm.receive(7)
|
||||
rxObj = rfm.receive(7)
|
||||
|
||||
try:
|
||||
sensorObj = rawsensor.CreateSensor(rxObj)
|
||||
sensorData = sensorObj.GetData()
|
||||
payload = {}
|
||||
ID = sensorData["ID"]
|
||||
payload["ID"] = ID
|
||||
T = sensorData["T"][0]
|
||||
payload["T"] = T
|
||||
except:
|
||||
continue
|
||||
try:
|
||||
sensorObj = sensors.rawsensor.CreateSensor(rxObj)
|
||||
sensorData = sensorObj.GetData()
|
||||
payload = {}
|
||||
ID = sensorData["ID"]
|
||||
payload["ID"] = ID
|
||||
T = sensorData["T"][0]
|
||||
payload["T"] = T
|
||||
except:
|
||||
continue
|
||||
|
||||
payload["rssi"] = rxObj[1]
|
||||
payload["afc"] = rxObj[2]
|
||||
payload["batlo"] = sensorData['batlo']
|
||||
payload["init"] = sensorData["init"]
|
||||
lock.acquire()
|
||||
for csens in config["sensors"]:
|
||||
if sensorData['ID'] == csens["id"]:
|
||||
payload["room"] = csens["name"]
|
||||
break
|
||||
payload["rssi"] = rxObj[1]
|
||||
payload["afc"] = rxObj[2]
|
||||
payload["batlo"] = sensorData['batlo']
|
||||
payload["init"] = sensorData["init"]
|
||||
lock.acquire()
|
||||
for csens in config["sensors"]:
|
||||
if sensorData['ID'] == csens["id"]:
|
||||
payload["room"] = csens["name"]
|
||||
break
|
||||
|
||||
if 'RH' in sensorData:
|
||||
RH = int(sensorData['RH'][0])
|
||||
payload["RH"] = RH
|
||||
a = 7.5
|
||||
b = 237.4
|
||||
SDD = 6.1078 * 10**(a*T/(b+T))
|
||||
if 'RH' in sensorData:
|
||||
RH = int(sensorData['RH'][0])
|
||||
payload["RH"] = RH
|
||||
a = 7.5
|
||||
b = 237.4
|
||||
SDD = 6.1078 * 10**(a*T/(b+T))
|
||||
|
||||
DD = RH / 100.0 * SDD
|
||||
v = math.log10(DD/6.1078)
|
||||
payload["DEW"] = round(b*v/(a-v), 1)
|
||||
payload["AH"] = round(10**5 * 18.016/8314.3 * DD/(T+273.15), 1)
|
||||
payload["SDD"] = SDD
|
||||
payload["DD"] = DD
|
||||
DD = RH / 100.0 * SDD
|
||||
v = math.log10(DD/6.1078)
|
||||
payload["DEW"] = round(b*v/(a-v), 1)
|
||||
payload["AH"] = round(10**5 * 18.016/8314.3 * DD/(T+273.15), 1)
|
||||
payload["SDD"] = SDD
|
||||
payload["DD"] = DD
|
||||
|
||||
DD = RH / 80.0 * SDD
|
||||
v = math.log10(DD/6.1078)
|
||||
payload["DEW80"] = round(b*v/(a-v), 1)
|
||||
DD = RH / 80.0 * SDD
|
||||
v = math.log10(DD/6.1078)
|
||||
payload["DEW80"] = round(b*v/(a-v), 1)
|
||||
|
||||
DD = RH / 60.0 * SDD
|
||||
v = math.log10(DD/6.1078)
|
||||
payload["DEW60"] = round(b*v/(a-v), 1)
|
||||
DD = RH / 60.0 * SDD
|
||||
v = math.log10(DD/6.1078)
|
||||
payload["DEW60"] = round(b*v/(a-v), 1)
|
||||
|
||||
if not ID in cache:
|
||||
cache[ID] = {}
|
||||
cache[ID]["count"] = 1
|
||||
cache[ID]["payload"] = payload
|
||||
cache[ID]["payload"]["tMin"] = T
|
||||
cache[ID]["payload"]["tMax"] = T
|
||||
else:
|
||||
payload["tMin"] = cache[ID]["payload"]["tMin"]
|
||||
payload["tMax"] = cache[ID]["payload"]["tMax"]
|
||||
if payload["tMin"] > T:
|
||||
payload["tMin"] = T
|
||||
if payload["tMax"] < T:
|
||||
payload["tMax"] = T
|
||||
|
||||
cache[ID]["payload"] = payload
|
||||
|
||||
if not ID in cache:
|
||||
cache[ID] = {}
|
||||
cache[ID]["count"] = 1
|
||||
cache[ID]["payload"] = payload
|
||||
cache[ID]["payload"]["tMin"] = T
|
||||
cache[ID]["payload"]["tMax"] = T
|
||||
else:
|
||||
payload["tMin"] = cache[ID]["payload"]["tMin"]
|
||||
payload["tMax"] = cache[ID]["payload"]["tMax"]
|
||||
if payload["tMin"] > T:
|
||||
payload["tMin"] = T
|
||||
if payload["tMax"] < T:
|
||||
payload["tMax"] = T
|
||||
|
||||
cache[ID]["payload"] = payload
|
||||
cache[ID]["ts"] = datetime.now()
|
||||
cache[ID]["count"] += 1
|
||||
|
||||
cache[ID]["ts"] = datetime.now()
|
||||
cache[ID]["count"] += 1
|
||||
line = u" ID: {:2} ".format(ID);
|
||||
line += u'room {:12} '.format(payload["room"][:12] if ("room" in payload) else "---")
|
||||
line += u' T: {:5} \u00b0C '.format(payload["T"])
|
||||
if "RH" in payload:
|
||||
line += 'RH: {:2} % '.format(payload["RH"])
|
||||
line += "battery: " + ("LOW " if payload["batlo"] else "OK ")
|
||||
line += "init: " + ("true " if payload["init"] else "false ")
|
||||
|
||||
line = u" ID: {:2} ".format(ID);
|
||||
line += u'room {:12} '.format(payload["room"][:12] if ("room" in payload) else "---")
|
||||
line += u' T: {:5} \u00b0C '.format(payload["T"])
|
||||
if "RH" in payload:
|
||||
line += 'RH: {:2} % '.format(payload["RH"])
|
||||
line += "battery: " + ("LOW " if payload["batlo"] else "OK ")
|
||||
line += "init: " + ("true " if payload["init"] else "false ")
|
||||
print('------------------------------------------------------------------------------')
|
||||
print(line)
|
||||
lock.release()
|
||||
|
||||
print('------------------------------------------------------------------------------')
|
||||
print(line)
|
||||
lock.release()
|
||||
try:
|
||||
if influxClient:
|
||||
writeInflux(payload)
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
if influxClient:
|
||||
writeInflux(payload)
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
if mqttClient:
|
||||
mqttClient.publish('home/lacrosse/'+ payload['ID'], json.dumps(payload))
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
if mqttClient:
|
||||
mqttClient.publish('home/lacrosse/'+ payload['ID'], json.dumps(payload))
|
||||
except:
|
||||
pass
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python2.7
|
||||
#!/usr/bin/env python
|
||||
|
||||
from raspyrfm import *
|
||||
import sys
|
||||
|
@ -92,11 +92,11 @@ def Decode(frame):
|
|||
valve = payload[1]
|
||||
dst = payload[2] / 2.0
|
||||
info += ", mode " + str(devflags & 0x03)
|
||||
if (devflags & (1<<7)) <> 0:
|
||||
if (devflags & (1<<7)) != 0:
|
||||
info += ", bat err"
|
||||
if (devflags & (1<<6)) <> 0:
|
||||
if (devflags & (1<<6)) != 0:
|
||||
info += ", com err"
|
||||
if (devflags & (1<<5)) <> 0:
|
||||
if (devflags & (1<<5)) != 0:
|
||||
info += ", locked"
|
||||
info += ", valve " + str(valve) + "%"
|
||||
info += ", set T " + str(dst)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python2.7
|
||||
#!/usr/bin/env python
|
||||
|
||||
import rcprotocols
|
||||
import time
|
||||
|
@ -8,30 +8,18 @@ mqttClient = mqtt.Client()
|
|||
mqttClient.connect("localhost", 1883, 60)
|
||||
mqttClient.loop_start()
|
||||
|
||||
rx = rcprotocols.PulseReceiver(1)
|
||||
def publish(proto, params):
|
||||
print("Publish: " + str(proto) + " / " + params)
|
||||
mqttClient.publish("home/rcbuttons/" + proto, params)
|
||||
|
||||
lastEvents = {}
|
||||
|
||||
def publish(proto, code):
|
||||
print("Publish: " + str(proto) + " / " + str(code))
|
||||
mqttClient.publish("home/rcbuttons/" + proto, code)
|
||||
def rxcb(dec, train):
|
||||
if dec is None:
|
||||
print("raw", train)
|
||||
return
|
||||
for d in dec:
|
||||
publish(d["protocol"], str(d["params"]))
|
||||
|
||||
rctrx = rcprotocols.RcTransceiver(1, 433.92, rxcb)
|
||||
|
||||
while True:
|
||||
time.sleep(0.1)
|
||||
evts = rx.getEvents()
|
||||
if evts:
|
||||
for e in evts:
|
||||
if e["protocol"] in lastEvents:
|
||||
le = lastEvents[e["protocol"]]
|
||||
if e["code"] != le["code"]:
|
||||
publish(e["protocol"], e["code"])
|
||||
le["code"] = e["code"]
|
||||
elif (time.time() - le["ts"] > 1):
|
||||
publish(e["protocol"], e["code"])
|
||||
le["ts"] = time.time()
|
||||
else:
|
||||
lastEvents[e["protocol"]] = {
|
||||
"ts": time.time(),
|
||||
"code": e["code"]
|
||||
}
|
||||
publish(e["protocol"], e["code"])
|
||||
time.sleep(1)
|
||||
|
|
|
@ -12,7 +12,10 @@ PARAM_COMMAND = ('a', 'command')
|
|||
PARAM_CODE = ('c', 'code')
|
||||
PARAM_DIPS = ('d', 'dips')
|
||||
|
||||
class RcProtocol:
|
||||
CLASS_RCSWITCH = "switch"
|
||||
CLASS_RCWEATHER = "weather"
|
||||
|
||||
class RcPulse:
|
||||
def __init__(self):
|
||||
self.__numbits = 0
|
||||
self._ookdata = bytearray()
|
||||
|
@ -22,21 +25,23 @@ class RcProtocol:
|
|||
self._lastdecode = None
|
||||
self._lastdecodetime = 0
|
||||
|
||||
sympulses = []
|
||||
for i in self._symbols:
|
||||
sympulses += self._symbols[i]
|
||||
sympulses.sort(reverse=True)
|
||||
i = 0
|
||||
while i<len(sympulses) - 1:
|
||||
if (sympulses[i] == sympulses[i+1]):
|
||||
del sympulses[i]
|
||||
else:
|
||||
i += 1
|
||||
p1 = sympulses.pop(0)
|
||||
p2 = sympulses.pop(0)
|
||||
f = (1.0 * p1 / p2 - 1) / (1.0 * p1/p2 + 2)
|
||||
self._minwidth = self._timebase - self._timebase * f
|
||||
self._maxwidth = self._timebase + self._timebase * f
|
||||
symset = set()
|
||||
for k in self._symbols:
|
||||
symset |= set(self._symbols[k])
|
||||
|
||||
symlist = list(symset)
|
||||
symlist.sort()
|
||||
q = 0
|
||||
for i in range(len(symlist) - 1):
|
||||
if 1.0 * symlist[i] / symlist[i+1] > q:
|
||||
q = 1.0 * symlist[i] / symlist[i+1]
|
||||
p1 = 1.0 * symlist[i]
|
||||
p2 = 1.0 * symlist[i+1]
|
||||
|
||||
f = (p2-p1) / (p2+p1)
|
||||
|
||||
self._minwidth = self._timebase * (1 - f)
|
||||
self._maxwidth = self._timebase * (1 + f)
|
||||
|
||||
def _reset(self):
|
||||
self.__numbits = 0
|
||||
|
@ -142,24 +147,25 @@ class RcProtocol:
|
|||
def encode(self, params):
|
||||
pass
|
||||
|
||||
class TristateBase(RcProtocol): #Baseclass for old intertechno, Brennenstuhl, ...
|
||||
class TristateBase(RcPulse): #Baseclass for old intertechno, Brennenstuhl, ...
|
||||
def __init__(self):
|
||||
self._timebase = 300
|
||||
if not hasattr(self, "_timebase"):
|
||||
self._timebase = 300
|
||||
self._repetitions = 4
|
||||
self._pattern = "[01fF]{12}"
|
||||
self._pattern = "[01F]{12}"
|
||||
self._symbols = {
|
||||
'0': [1, 4, 1, 4],
|
||||
'1': [4, 1, 4, 1],
|
||||
'f': [1, 4, 4, 1],
|
||||
'F': [1, 4, 4, 1],
|
||||
'0': [1, 3, 1, 3],
|
||||
'1': [3, 1, 3, 1],
|
||||
'F': [1, 3, 3, 1],
|
||||
}
|
||||
self._footer = [1, 31]
|
||||
RcProtocol.__init__(self)
|
||||
self._class = CLASS_RCSWITCH
|
||||
RcPulse.__init__(self)
|
||||
|
||||
def _encode_int(self, ival, digits):
|
||||
code = ""
|
||||
for i in range(digits):
|
||||
code += "f" if (ival & 0x01) > 0 else "0"
|
||||
code += "F" if (ival & 0x01) > 0 else "0"
|
||||
ival >>= 1
|
||||
return code
|
||||
|
||||
|
@ -167,20 +173,20 @@ class TristateBase(RcProtocol): #Baseclass for old intertechno, Brennenstuhl, ..
|
|||
i = 0
|
||||
while tristateval != "":
|
||||
i <<= 1
|
||||
if tristateval[-1] != '0':
|
||||
if tristateval[-1] == "F":
|
||||
i |= 1
|
||||
tristateval = tristateval[:-1]
|
||||
return i
|
||||
|
||||
|
||||
class Tristate(TristateBase): #old intertechno
|
||||
class Tristate(TristateBase):
|
||||
def __init__(self):
|
||||
self._name = "tristate"
|
||||
TristateBase.__init__(self)
|
||||
self.params = [PARAM_CODE]
|
||||
|
||||
def encode(self, params, timebase=None, repetitions=None):
|
||||
return self._build_frame(params["code"], timebase, repetitions)
|
||||
return self._build_frame(params["code"].upper(), timebase, repetitions)
|
||||
|
||||
def decode(self, pulsetrain):
|
||||
symbols, tb, rep = self._decode_symbols(pulsetrain[0:-2])
|
||||
|
@ -199,7 +205,7 @@ class ITTristate(TristateBase): #old intertechno
|
|||
symbols += self._encode_int(ord(params["house"][0]) - ord('A'), 4)
|
||||
symbols += self._encode_int(int(params["unit"]) - 1, 2)
|
||||
symbols += self._encode_int(int(params["group"]) - 1, 2)
|
||||
symbols += "0f"
|
||||
symbols += "0F"
|
||||
symbols += self._encode_command(params["command"])
|
||||
return self._build_frame(symbols, timebase, repetitions)
|
||||
|
||||
|
@ -210,10 +216,10 @@ class ITTristate(TristateBase): #old intertechno
|
|||
"house": chr(self._decode_int(symbols[:4]) + ord('A')),
|
||||
"unit": self._decode_int(symbols[4:6]) + 1,
|
||||
"group": self._decode_int(symbols[6:8]) + 1,
|
||||
"command": self._decode_command(symbols[10:12].upper()),
|
||||
"command": self._decode_command(symbols[10:12]),
|
||||
}, tb, rep
|
||||
|
||||
class Brennenstuhl(TristateBase): #old intertechno
|
||||
class Brennenstuhl(TristateBase):
|
||||
def __init__(self):
|
||||
self._name = "brennenstuhl"
|
||||
TristateBase.__init__(self)
|
||||
|
@ -248,7 +254,7 @@ class Brennenstuhl(TristateBase): #old intertechno
|
|||
"command": self._decode_command(symbols[10:12].upper()),
|
||||
}, tb, rep
|
||||
|
||||
class PPM1(RcProtocol): #Intertechno, Hama, ...
|
||||
class PPM1(RcPulse): #Intertechno, Hama, Nexa, Telldus, ...
|
||||
'''
|
||||
PDM1: Pulse Position Modulation
|
||||
Every bit consists of 2 shortpulses. Long distance between these pulses 2 pulses -> 1, else -> 0
|
||||
|
@ -265,15 +271,16 @@ class PPM1(RcProtocol): #Intertechno, Hama, ...
|
|||
'1': [1, 5, 1, 1],
|
||||
}
|
||||
self._footer = [1, 39]
|
||||
RcProtocol.__init__(self)
|
||||
self._class = CLASS_RCSWITCH
|
||||
RcPulse.__init__(self)
|
||||
|
||||
class Intertechno(PPM1):
|
||||
def __init__(self):
|
||||
PPM1.__init__(self)
|
||||
self._name = "intertechno"
|
||||
self._timebase = 275
|
||||
self.params = [PARAM_ID, PARAM_UNIT, PARAM_COMMAND]
|
||||
self._commands = {"on": "1", "off": "0"}
|
||||
self._timebase = 275
|
||||
PPM1.__init__(self)
|
||||
|
||||
def _encode_unit(self, unit):
|
||||
return "{:04b}".format(int(unit) - 1)
|
||||
|
@ -311,9 +318,9 @@ class Hama(Intertechno):
|
|||
return 16 - int(unit, 2)
|
||||
|
||||
|
||||
class PWM1(RcProtocol):
|
||||
class PWM1(RcPulse):
|
||||
'''
|
||||
PWM1: Pulse Width Modulation
|
||||
PWM1: Pulse Width Modulation 24 bit
|
||||
Wide pulse -> 1, small pulse -> 0
|
||||
Frame: header, payload, footer
|
||||
Used by Emylo, Logilight, ...
|
||||
|
@ -327,14 +334,15 @@ class PWM1(RcProtocol):
|
|||
'0': [1, 3],
|
||||
}
|
||||
self._footer = [1, 31]
|
||||
RcProtocol.__init__(self)
|
||||
self._class = CLASS_RCSWITCH
|
||||
RcPulse.__init__(self)
|
||||
|
||||
class Logilight(PWM1):
|
||||
def __init__(self):
|
||||
PWM1.__init__(self)
|
||||
self._name = "logilight"
|
||||
self.params = [PARAM_ID, PARAM_UNIT, PARAM_COMMAND]
|
||||
self._commands = {"on": "1", "learn": "1", "off": "0"}
|
||||
PWM1.__init__(self)
|
||||
|
||||
def _encode_unit(self, unit):
|
||||
res = ""
|
||||
|
@ -373,10 +381,10 @@ class Logilight(PWM1):
|
|||
|
||||
class Emylo(PWM1):
|
||||
def __init__(self):
|
||||
PWM1.__init__(self)
|
||||
self._name = "emylo"
|
||||
self.params = [PARAM_ID, PARAM_COMMAND]
|
||||
self._commands = {'A': '0001', 'B': '0010', 'C': '0100', 'D': '1000'}
|
||||
PWM1.__init__(self)
|
||||
|
||||
def encode(self, params, timebase=None, repetitions=None):
|
||||
symbols = ""
|
||||
|
@ -392,7 +400,7 @@ class Emylo(PWM1):
|
|||
"command": self._decode_command(symbols[-4:])
|
||||
}, tb, rep
|
||||
|
||||
class FS20(RcProtocol):
|
||||
class FS20(RcPulse):
|
||||
def __init__(self):
|
||||
self._name = "fs20"
|
||||
self._timebase = 200
|
||||
|
@ -405,7 +413,8 @@ class FS20(RcProtocol):
|
|||
self._header = [2, 2] * 12 + [3, 3]
|
||||
self._footer = [1, 100]
|
||||
self.params = [PARAM_ID,PARAM_UNIT, PARAM_COMMAND]
|
||||
RcProtocol.__init__(self)
|
||||
self._class = CLASS_RCSWITCH
|
||||
RcPulse.__init__(self)
|
||||
|
||||
def __encode_byte(self, b):
|
||||
b &= 0xFF
|
||||
|
@ -439,7 +448,7 @@ class FS20(RcProtocol):
|
|||
"command": int(symbols[40:48], 2),
|
||||
}, tb, rep
|
||||
|
||||
class Voltcraft(RcProtocol):
|
||||
class Voltcraft(RcPulse):
|
||||
'''
|
||||
PPM: Pulse Position Modulation
|
||||
Pulse in middle of a symbol: 0, end of symbol: 1
|
||||
|
@ -458,7 +467,8 @@ class Voltcraft(RcProtocol):
|
|||
self._footer = [132]
|
||||
self.params = [PARAM_ID, PARAM_UNIT, PARAM_COMMAND]
|
||||
self._commands = {"off": "000", "alloff": "100", "on": "010", "allon": "110", "dimup": "101", "dimdown": "111"}
|
||||
RcProtocol.__init__(self)
|
||||
self._class = CLASS_RCSWITCH
|
||||
RcPulse.__init__(self)
|
||||
|
||||
def encode(self, params, timebase=None, repetitions=None):
|
||||
if params["command"] in ["on", "off"]:
|
||||
|
@ -483,27 +493,11 @@ class Voltcraft(RcProtocol):
|
|||
"command": self._decode_command(symbols[14:17])
|
||||
}, tb, rep
|
||||
|
||||
class PWM2(RcProtocol):
|
||||
class PilotaCasa(RcPulse):
|
||||
'''
|
||||
PWM2: Pulse Width Modulation
|
||||
Pulse Width Modulation 32 bit
|
||||
Wide pulse -> 0, small pulse -> 1
|
||||
Frame: header, payload, footer
|
||||
Used by Pilota casa
|
||||
'''
|
||||
def __init__(self):
|
||||
self._name = "pwm2"
|
||||
self._timebase = 600
|
||||
self._repetitions = 10
|
||||
self._pattern = "[01]{32}"
|
||||
self._symbols = {
|
||||
'1': [1, 2],
|
||||
'0': [2, 1],
|
||||
}
|
||||
self._footer = [1, 11]
|
||||
self.params = [PARAM_CODE]
|
||||
RcProtocol.__init__(self)
|
||||
|
||||
class PilotaCasa(PWM2):
|
||||
__codes = {
|
||||
'110001': (1, 1, 'on'), '111110': (1, 1, 'off'),
|
||||
'011001': (1, 2, 'on'), '010001': (1, 2, 'off'),
|
||||
|
@ -521,9 +515,18 @@ class PilotaCasa(PWM2):
|
|||
}
|
||||
|
||||
def __init__(self):
|
||||
PWM2.__init__(self)
|
||||
self._name = "pilota"
|
||||
self._timebase = 550
|
||||
self._repetitions = 5
|
||||
self._pattern = "[01]{32}"
|
||||
self._symbols = {
|
||||
'1': [1, 2],
|
||||
'0': [2, 1],
|
||||
}
|
||||
self._footer = [1, 12]
|
||||
self.params = [PARAM_ID, PARAM_GROUP, PARAM_UNIT, PARAM_COMMAND]
|
||||
self._class = CLASS_RCSWITCH
|
||||
RcPulse.__init__(self)
|
||||
|
||||
def encode(self, params, timebase=None, repetitions=None):
|
||||
symbols = '01'
|
||||
|
@ -551,36 +554,33 @@ class PilotaCasa(PWM2):
|
|||
"command": c[2],
|
||||
}, tb, rep
|
||||
|
||||
class PCPIR(RcProtocol): #pilota casa PIR sensor
|
||||
class PCPIR(TristateBase): #pilota casa PIR sensor
|
||||
'''
|
||||
Pilota Casa IR sensor
|
||||
'''
|
||||
def __init__(self):
|
||||
self._name = "pcpir"
|
||||
self._timebase = 400
|
||||
self._repetitions = 5
|
||||
self._pattern = "[01]{12}"
|
||||
self._symbols = {
|
||||
'1': [1, 3, 1, 3],
|
||||
'0': [1, 3, 3, 1],
|
||||
}
|
||||
RcProtocol.__init__(self)
|
||||
self._parser.add_argument("-c", "--code", required=True)
|
||||
self.params = [PARAM_ID, PARAM_COMMAND]
|
||||
self._timebase = 500
|
||||
self._commands = {"off": "0", "on": "F"}
|
||||
TristateBase.__init__(self)
|
||||
|
||||
def encode(self, params, timebase=None, repetitions=None):
|
||||
symbols = ""
|
||||
return self._build_frame(symbols, timebase, repetitions)
|
||||
|
||||
def decode(self, pulsetrain):
|
||||
code, tb, rep = self._decode_symbols(pulsetrain[0:-2])
|
||||
if code:
|
||||
symbols, tb, rep = self._decode_symbols(pulsetrain[0:-2])
|
||||
if symbols:
|
||||
print("PCIR", symbols, pulsetrain)
|
||||
return {
|
||||
"protocol": self._name,
|
||||
"code": code,
|
||||
"timebase": tb,
|
||||
}, rep
|
||||
"id": self._decode_int(symbols[5:10]),
|
||||
"unit": self._decode_int(symbols[0:5]),
|
||||
"command": self._decode_command(symbols[11:12])
|
||||
}, tb, rep
|
||||
|
||||
def encode(self, args):
|
||||
self._reset()
|
||||
self._add_symbols(args.code)
|
||||
self._add_pulses([1, 12])
|
||||
self._add_finish()
|
||||
return self._ookdata, self._timebase, self._repetitions
|
||||
|
||||
class REVRitterShutter(RcProtocol):
|
||||
class REVRitterShutter(RcPulse):
|
||||
'''
|
||||
Pulse Width Modulation 24 bit,
|
||||
Short pulse: 0, long pulse: 1
|
||||
|
@ -597,7 +597,8 @@ class REVRitterShutter(RcProtocol):
|
|||
}
|
||||
self._footer = [1, 85]
|
||||
self.params = [PARAM_ID]
|
||||
RcProtocol.__init__(self)
|
||||
self._class = CLASS_RCSWITCH
|
||||
RcPulse.__init__(self)
|
||||
|
||||
def encode(self, params, timebase=None, repetitions=None):
|
||||
symbols = "{:024b}".format(int(params["id"]))
|
||||
|
@ -610,6 +611,91 @@ class REVRitterShutter(RcProtocol):
|
|||
"id": int(symbols[0:24], 2),
|
||||
}, tb, rep
|
||||
|
||||
class WH2(RcPulse):
|
||||
'''
|
||||
Temperature & humidity sensor WH2, Telldus
|
||||
Pulse Duration Modulation
|
||||
Short, middle = 1, long middle = 0
|
||||
'''
|
||||
def __init__(self):
|
||||
self._name = "wh2"
|
||||
self._class = CLASS_RCWEATHER
|
||||
self._timebase = 500
|
||||
self._pattern = "11111111[01]{39}"
|
||||
self._symbols = {
|
||||
'1': [1, 2],
|
||||
'0': [3, 2],
|
||||
}
|
||||
self._footer = [2, 49]
|
||||
RcPulse.__init__(self)
|
||||
|
||||
def decode(self, pulsetrain):
|
||||
symbols, tb, rep = self._decode_symbols(pulsetrain[0:-2])
|
||||
if symbols:
|
||||
symbols += "0"
|
||||
res = {}
|
||||
|
||||
res["id"] = "{:02x}".format(int(symbols[12:20], 2))
|
||||
T = int(symbols[20:32], 2)
|
||||
if T >= 1<<11:
|
||||
T -= 1<<12
|
||||
T /= 10.0
|
||||
res["T"] = T
|
||||
|
||||
RH = int(symbols[32:40], 2)
|
||||
if RH != 0xFF:
|
||||
res["RH"] = RH
|
||||
|
||||
return res, tb, rep
|
||||
|
||||
class WS7000(RcPulse):
|
||||
'''
|
||||
Temperature & humidity sensor LaCrosee/ELV
|
||||
Pulse Width Modulation
|
||||
Short = 1, long = 2
|
||||
'''
|
||||
def __init__(self):
|
||||
self._name = "ws7000"
|
||||
self._class = CLASS_RCWEATHER
|
||||
self._timebase = 400
|
||||
self._pattern = "^0{5,}1([01]{4}1){6,}[01]{4,5}$"
|
||||
self._symbols = {
|
||||
'1': [1, 2],
|
||||
'0': [2, 1],
|
||||
}
|
||||
self._footer = [2, 49]
|
||||
RcPulse.__init__(self)
|
||||
|
||||
def decode(self, pulsetrain):
|
||||
symbols, tb, rep = self._decode_symbols(pulsetrain[0:-2])
|
||||
if symbols:
|
||||
symbols = symbols[symbols.find("000001") + 6:]
|
||||
n = [] #nibbles
|
||||
i = 0
|
||||
check = 0
|
||||
while i <= len(symbols) - 4:
|
||||
n.append(int(symbols[i:i+4][::-1], 2))
|
||||
i += 5
|
||||
if i <= len(symbols) - 4:
|
||||
check ^= n[-1]
|
||||
if check != 0:
|
||||
return
|
||||
|
||||
res = {}
|
||||
res["id"] = (n[0] << 4) | (n[1] & 0x07)
|
||||
|
||||
if n[0] == 1: #WS7000 has subtypes
|
||||
#WS7000-22/25
|
||||
t = n[2] * 0.1 + n[3] * 1 + n[4] * 10
|
||||
if (n[1] & 0x8) == 0x8:
|
||||
t = -t
|
||||
res["T"] = t
|
||||
res["unit"] = n[1] & 0x7
|
||||
h = n[5] * 0.1 + n[6] * 1 + n[7] * 10
|
||||
if h > 0:
|
||||
res["RH"] = h
|
||||
return res, tb, rep
|
||||
|
||||
protocols = [
|
||||
Tristate(),
|
||||
ITTristate(),
|
||||
|
@ -618,13 +704,13 @@ protocols = [
|
|||
Hama(),
|
||||
Logilight(),
|
||||
Emylo(),
|
||||
#PWM2(),
|
||||
Voltcraft(),
|
||||
#PCPIR(),
|
||||
#PDM1(),
|
||||
PCPIR(),
|
||||
FS20(),
|
||||
PilotaCasa(),
|
||||
REVRitterShutter()
|
||||
REVRitterShutter(),
|
||||
WH2(),
|
||||
WS7000(),
|
||||
]
|
||||
|
||||
def get_protocol(name):
|
||||
|
@ -633,7 +719,6 @@ def get_protocol(name):
|
|||
return p
|
||||
return None
|
||||
|
||||
|
||||
RXDATARATE = 20.0 #kbit/s
|
||||
class RfmPulseTRX(threading.Thread):
|
||||
def __init__(self, module, rxcb, frequency):
|
||||
|
@ -742,7 +827,7 @@ class RcTransceiver(threading.Thread):
|
|||
if params:
|
||||
succ = True
|
||||
if not rep:
|
||||
res.append({"protocol": p._name, "params": params})
|
||||
res.append({"protocol": p._name, "class": p._class, "params": params})
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python2.7
|
||||
#!/usr/bin/env python
|
||||
|
||||
from raspyrfm import *
|
||||
import sys
|
||||
|
@ -50,4 +50,4 @@ while True:
|
|||
if (state == "on"):
|
||||
state = "off"
|
||||
else:
|
||||
state = "on"
|
||||
state = "on"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python2.7
|
||||
#!/usr/bin/env python
|
||||
|
||||
import socket
|
||||
import threading
|
||||
|
@ -27,10 +27,11 @@ def rxcb(dec, train):
|
|||
if len(dec) > 0:
|
||||
payload = {"decode": dec, "raw": train}
|
||||
|
||||
print(payload)
|
||||
if payload is not None:
|
||||
print("RX", payload)
|
||||
s = json.dumps(payload) + "\n"
|
||||
for client in clients:
|
||||
client.send(payload)
|
||||
client.send(s)
|
||||
|
||||
|
||||
if not raspyrfm_test(args.module, RFM69):
|
||||
|
@ -38,28 +39,32 @@ if not raspyrfm_test(args.module, RFM69):
|
|||
exit()
|
||||
|
||||
rctrx = rcprotocols.RcTransceiver(args.module, args.frequency, rxcb)
|
||||
|
||||
lock = threading.Lock()
|
||||
lock = threading.Lock()
|
||||
|
||||
class clientthread(threading.Thread):
|
||||
def __init__(self, socket):
|
||||
self.__socket = socket
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
def send(self, obj):
|
||||
self.__socket.send(json.dumps(obj))
|
||||
def send(self, s):
|
||||
self.__socket.sendall(s.encode())
|
||||
|
||||
def run(self):
|
||||
buf = ""
|
||||
while True:
|
||||
chunk = self.__socket.recv(1024)
|
||||
chunk = self.__socket.recv(32).decode()
|
||||
if len(chunk) == 0:
|
||||
del self.__socket
|
||||
break
|
||||
lock.acquire()
|
||||
try:
|
||||
#print(chunk)
|
||||
lock.acquire()
|
||||
d = json.loads(chunk)
|
||||
rctrx.send(d["protocol"], d["params"])
|
||||
buf += chunk
|
||||
while "\n" in buf:
|
||||
line = buf[:buf.find("\n")]
|
||||
buf = buf[buf.find("\n") + 1:]
|
||||
d = json.loads(line)
|
||||
print("TX", d)
|
||||
rctrx.send(d["protocol"], d["params"])
|
||||
except:
|
||||
pass
|
||||
lock.release()
|
||||
|
@ -70,4 +75,4 @@ while True:
|
|||
ct = clientthread(client)
|
||||
ct.daemon = True
|
||||
ct.start()
|
||||
clients.append(ct)
|
||||
clients.append(ct)
|
||||
|
|
|
@ -35,7 +35,7 @@ def RaspyRFM(mod, type):
|
|||
|
||||
"""
|
||||
s = __get_hw_params(mod)
|
||||
|
||||
|
||||
if s:
|
||||
if type == RFM69:
|
||||
return rfm69.Rfm69(s[0], s[1])
|
||||
|
@ -45,4 +45,4 @@ def RaspyRFM(mod, type):
|
|||
def raspyrfm_test(mod, type):
|
||||
s = __get_hw_params(mod)
|
||||
if s:
|
||||
return rfm69.Rfm69.test(s[0], s[1])
|
||||
return rfm69.Rfm69.test(s[0], s[1])
|
||||
|
|
Loading…
Reference in a new issue