Better timing tolerance

Add weather sensors wh2, wh7000
some python3 issues
fix docu & PC PIR
This commit is contained in:
S. Seegel 2020-12-16 02:32:32 +01:00
parent 3e70559ef2
commit 01ddd7e3cc
12 changed files with 476 additions and 393 deletions

View file

@ -30,7 +30,7 @@ rfm.set_params(
## connair.py ## connair.py
emulate a gateway for controlling RC sockets via the app power-switch. Compatible to "Brennenstuhl Brematic", Intertechno "ITGW-433", "ConnAir" 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 ## emoncms.py
receive lacrosse-sensors with the RaspyRFM and post them to the open energy monitor, see https://openenergymonitor.org/ 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 ## Product
[Module RaspbyRFM Seegel Systeme](http://www.seegel-systeme.de/produkt/raspyrfm-ii/) [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/)

View file

@ -1,4 +1,4 @@
#!/usr/bin/env python2.7 #!/usr/bin/env python
import socket import socket
from raspyrfm import * from raspyrfm import *

View file

@ -1,4 +1,4 @@
#!/usr/bin/env python2.7 #!/usr/bin/env python
from raspyrfm import * from raspyrfm import *
import sys import sys
@ -113,7 +113,7 @@ def calcword(datain):
result |= d result |= d
return result return result
print "Waiting for sensors..." print("Waiting for sensors...")
while 1: while 1:
data = rfm.receive(56) data = rfm.receive(56)
data = descramble(data[0]) data = descramble(data[0])

View file

@ -1,4 +1,4 @@
#!/usr/bin/env python2.7 #!/usr/bin/env python
from raspyrfm import * from raspyrfm import *
import sensors import sensors
@ -7,7 +7,6 @@ import time
import requests import requests
import json import json
URL = 'https://emoncms.org/input/post.json' URL = 'https://emoncms.org/input/post.json'
APIKEY = '123456789123456789' APIKEY = '123456789123456789'
@ -44,7 +43,7 @@ def LogSensor(data):
if s['sensorId'] == data['ID']: if s['sensorId'] == data['ID']:
if data['ID'] in lasttimes: if data['ID'] in lasttimes:
if time.time() - lasttimes[data['ID']] < s['minInterval']: if time.time() - lasttimes[data['ID']] < s['minInterval']:
print "discarded value" print("discarded value")
return return
lasttimes[data['ID']] = time.time() lasttimes[data['ID']] = time.time()
@ -55,9 +54,9 @@ def LogSensor(data):
payload = {'apikey': APIKEY, 'node': s['node'], 'json': json.dumps(values)} payload = {'apikey': APIKEY, 'node': s['node'], 'json': json.dumps(values)}
r = requests.get(URL, params = payload) r = requests.get(URL, params = payload)
print "Sending to emon:", payload, "Result:", r print("Sending to emon:", payload, "Result:", r)
return return
print "No match for ID" print("No match for ID")
if raspyrfm_test(2, RFM69): if raspyrfm_test(2, RFM69):
@ -65,7 +64,7 @@ if raspyrfm_test(2, RFM69):
elif raspyrfm_test(1, RFM69): elif raspyrfm_test(1, RFM69):
rfm = RaspyRFM(1, RFM69) #when using a single single 868 MHz RaspyRFM rfm = RaspyRFM(1, RFM69) #when using a single single 868 MHz RaspyRFM
else: else:
print "No RFM69 module found!" print("No RFM69 module found!")
exit() exit()
rfm.set_params( rfm.set_params(

View file

@ -1,4 +1,4 @@
#!/usr/bin/env python2.7 #!/usr/bin/env python
from raspyrfm import * from raspyrfm import *
import sensors import sensors
@ -12,7 +12,7 @@ if raspyrfm_test(2, RFM69):
rfm = RaspyRFM(2, RFM69) #when using the RaspyRFM twin rfm = RaspyRFM(2, RFM69) #when using the RaspyRFM twin
elif raspyrfm_test(1, RFM69): elif raspyrfm_test(1, RFM69):
print("Found RaspyRFM single") 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: else:
print("No RFM69 module found!") print("No RFM69 module found!")
exit() exit()

View file

@ -1,31 +1,38 @@
#!/usr/bin/env python2.7 #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from raspyrfm import * import raspyrfm
import sensors import sensors
from sensors import rawsensor
import sys import sys
import time import time
import threading import threading
import math import math
import json import json
from datetime import datetime from datetime import datetime
#import os
import SocketServer try:
import SimpleHTTPServer #python2.7
import urlparse 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() lock = threading.Lock()
with open("lacrossegw.conf") as jfile: with open("lacrossegw.conf") as jfile:
config = json.load(jfile) config = json.load(jfile)
if raspyrfm_test(2, RFM69): if raspyrfm.raspyrfm_test(2, raspyrfm.RFM69):
print("Found RaspyRFM twin") print("Found RaspyRFM twin")
rfm = RaspyRFM(2, RFM69) #when using the RaspyRFM twin rfm = raspyrfm.RaspyRFM(2, raspyrfm.RFM69) #when using the RaspyRFM twin
elif raspyrfm_test(1, RFM69): elif raspyrfm.raspyrfm_test(1, raspyrfm.RFM69):
print("Found RaspyRFM single") print("Found RaspyRFM single")
rfm = RaspyRFM(1, RFM69) #when using a single single 868 MHz RaspyRFM rfm = raspyrfm.RaspyRFM(1, raspyrfm.RFM69) #when using a single single 868 MHz RaspyRFM
else: else:
print("No RFM69 module found!") print("No RFM69 module found!")
exit() exit()
@ -71,12 +78,9 @@ except:
rfm.set_params( rfm.set_params(
Freq = 868.300, #MHz center frequency Freq = 868.300, #MHz center frequency
Datarate = 9.579, #kbit/s baudrate Datarate = 9.579, #kbit/s baudrate
ModulationType = rfm69.FSK, #modulation ModulationType = raspyrfm.rfm69.FSK, #modulation
Deviation = 30, #kHz frequency deviation OBW = 69.6/77.2 kHz, h = 6.3/3.5
SyncPattern = [0x2d, 0xd4], #syncword SyncPattern = [0x2d, 0xd4], #syncword
Bandwidth = 100, #kHz bandwidth Bandwidth = 100, #kHz bandwidth
#AfcBandwidth = 150,
#AfcFei = 0x0E,
RssiThresh = -100, #-100 dB RSSI threshold RssiThresh = -100, #-100 dB RSSI threshold
) )
@ -88,7 +92,7 @@ class BaudChanger(threading.Thread):
def run(self): def run(self):
while True: while True:
time.sleep(15) time.sleep(15)
print "Change baudrate" print("Change baudrate")
if self.baud: if self.baud:
rfm.set_params(Datarate = 9.579) rfm.set_params(Datarate = 9.579)
else: else:
@ -161,7 +165,7 @@ def getCacheSensor(id, sensorConfig = None):
return sensor return sensor
class MyHttpRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): class MyHttpRequestHandler(Handler):
def getjson(self): def getjson(self):
self.send_response(200) self.send_response(200)
self.send_header('Content-type', 'application/json') self.send_header('Content-type', 'application/json')
@ -174,7 +178,6 @@ class MyHttpRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
id = csens["id"] id = csens["id"]
sensor = getCacheSensor(id, csens) sensor = getCacheSensor(id, csens)
if sensor is not None: if sensor is not None:
#print("Sensor: ", sensor)
idlist.append(id) idlist.append(id)
else: else:
sensor = {} sensor = {}
@ -192,12 +195,12 @@ class MyHttpRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
lock.release() lock.release()
self.wfile.write(json.dumps(resp)) self.wfile.write(json.dumps(resp).encode())
def do_GET(self): def do_GET(self):
url = urlparse.urlparse(self.path) url = urlparse(self.path)
p = url.path p = url.path
q = urlparse.parse_qs(url.query) q = parse_qs(url.query)
if 'name' in q: if 'name' in q:
name = q['name'][0] name = q['name'][0]
@ -206,7 +209,7 @@ class MyHttpRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
elif p == '/': elif p == '/':
self.path = 'index.html' self.path = 'index.html'
return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self) return Handler.do_GET(self)
elif p == '/history' and influxClient and name: elif p == '/history' and influxClient and name:
resp = influxClient.query( resp = influxClient.query(
@ -216,13 +219,12 @@ class MyHttpRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
self.send_response(200) self.send_response(200)
self.send_header('Content-type', 'application/json') self.send_header('Content-type', 'application/json')
self.end_headers() self.end_headers()
self.wfile.write(json.dumps(resp.raw['series'][0]['values'])) self.wfile.write(json.dumps(resp.raw['series'][0]['values']).encode())
else: else:
return self.send_error(404, self.responses.get(404)[0]) return self.send_error(404, self.responses.get(404)[0])
class Server(SocketServer.ThreadingMixIn, SocketServer.TCPServer): class Server(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass pass
cache = {} cache = {}
@ -232,13 +234,13 @@ server_thread = threading.Thread(target=server.serve_forever)
server_thread.daemon = True server_thread.daemon = True
server_thread.start() server_thread.start()
print "Waiting for sensors..." print("Waiting for sensors...")
while 1: while 1:
rxObj = rfm.receive(7) rxObj = rfm.receive(7)
try: try:
sensorObj = rawsensor.CreateSensor(rxObj) sensorObj = sensors.rawsensor.CreateSensor(rxObj)
sensorData = sensorObj.GetData() sensorData = sensorObj.GetData()
payload = {} payload = {}
ID = sensorData["ID"] ID = sensorData["ID"]
@ -280,7 +282,6 @@ while 1:
v = math.log10(DD/6.1078) v = math.log10(DD/6.1078)
payload["DEW60"] = round(b*v/(a-v), 1) payload["DEW60"] = round(b*v/(a-v), 1)
if not ID in cache: if not ID in cache:
cache[ID] = {} cache[ID] = {}
cache[ID]["count"] = 1 cache[ID]["count"] = 1

View file

@ -1,4 +1,4 @@
#!/usr/bin/env python2.7 #!/usr/bin/env python
from raspyrfm import * from raspyrfm import *
import sys import sys
@ -92,11 +92,11 @@ def Decode(frame):
valve = payload[1] valve = payload[1]
dst = payload[2] / 2.0 dst = payload[2] / 2.0
info += ", mode " + str(devflags & 0x03) info += ", mode " + str(devflags & 0x03)
if (devflags & (1<<7)) <> 0: if (devflags & (1<<7)) != 0:
info += ", bat err" info += ", bat err"
if (devflags & (1<<6)) <> 0: if (devflags & (1<<6)) != 0:
info += ", com err" info += ", com err"
if (devflags & (1<<5)) <> 0: if (devflags & (1<<5)) != 0:
info += ", locked" info += ", locked"
info += ", valve " + str(valve) + "%" info += ", valve " + str(valve) + "%"
info += ", set T " + str(dst) info += ", set T " + str(dst)

View file

@ -1,4 +1,4 @@
#!/usr/bin/env python2.7 #!/usr/bin/env python
import rcprotocols import rcprotocols
import time import time
@ -8,30 +8,18 @@ mqttClient = mqtt.Client()
mqttClient.connect("localhost", 1883, 60) mqttClient.connect("localhost", 1883, 60)
mqttClient.loop_start() mqttClient.loop_start()
rx = rcprotocols.PulseReceiver(1) def publish(proto, params):
print("Publish: " + str(proto) + " / " + params)
mqttClient.publish("home/rcbuttons/" + proto, params)
lastEvents = {} def rxcb(dec, train):
if dec is None:
print("raw", train)
return
for d in dec:
publish(d["protocol"], str(d["params"]))
def publish(proto, code): rctrx = rcprotocols.RcTransceiver(1, 433.92, rxcb)
print("Publish: " + str(proto) + " / " + str(code))
mqttClient.publish("home/rcbuttons/" + proto, code)
while True: while True:
time.sleep(0.1) time.sleep(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"])

View file

@ -12,7 +12,10 @@ PARAM_COMMAND = ('a', 'command')
PARAM_CODE = ('c', 'code') PARAM_CODE = ('c', 'code')
PARAM_DIPS = ('d', 'dips') PARAM_DIPS = ('d', 'dips')
class RcProtocol: CLASS_RCSWITCH = "switch"
CLASS_RCWEATHER = "weather"
class RcPulse:
def __init__(self): def __init__(self):
self.__numbits = 0 self.__numbits = 0
self._ookdata = bytearray() self._ookdata = bytearray()
@ -22,21 +25,23 @@ class RcProtocol:
self._lastdecode = None self._lastdecode = None
self._lastdecodetime = 0 self._lastdecodetime = 0
sympulses = [] symset = set()
for i in self._symbols: for k in self._symbols:
sympulses += self._symbols[i] symset |= set(self._symbols[k])
sympulses.sort(reverse=True)
i = 0 symlist = list(symset)
while i<len(sympulses) - 1: symlist.sort()
if (sympulses[i] == sympulses[i+1]): q = 0
del sympulses[i] for i in range(len(symlist) - 1):
else: if 1.0 * symlist[i] / symlist[i+1] > q:
i += 1 q = 1.0 * symlist[i] / symlist[i+1]
p1 = sympulses.pop(0) p1 = 1.0 * symlist[i]
p2 = sympulses.pop(0) p2 = 1.0 * symlist[i+1]
f = (1.0 * p1 / p2 - 1) / (1.0 * p1/p2 + 2)
self._minwidth = self._timebase - self._timebase * f f = (p2-p1) / (p2+p1)
self._maxwidth = self._timebase + self._timebase * f
self._minwidth = self._timebase * (1 - f)
self._maxwidth = self._timebase * (1 + f)
def _reset(self): def _reset(self):
self.__numbits = 0 self.__numbits = 0
@ -142,24 +147,25 @@ class RcProtocol:
def encode(self, params): def encode(self, params):
pass pass
class TristateBase(RcProtocol): #Baseclass for old intertechno, Brennenstuhl, ... class TristateBase(RcPulse): #Baseclass for old intertechno, Brennenstuhl, ...
def __init__(self): def __init__(self):
if not hasattr(self, "_timebase"):
self._timebase = 300 self._timebase = 300
self._repetitions = 4 self._repetitions = 4
self._pattern = "[01fF]{12}" self._pattern = "[01F]{12}"
self._symbols = { self._symbols = {
'0': [1, 4, 1, 4], '0': [1, 3, 1, 3],
'1': [4, 1, 4, 1], '1': [3, 1, 3, 1],
'f': [1, 4, 4, 1], 'F': [1, 3, 3, 1],
'F': [1, 4, 4, 1],
} }
self._footer = [1, 31] self._footer = [1, 31]
RcProtocol.__init__(self) self._class = CLASS_RCSWITCH
RcPulse.__init__(self)
def _encode_int(self, ival, digits): def _encode_int(self, ival, digits):
code = "" code = ""
for i in range(digits): for i in range(digits):
code += "f" if (ival & 0x01) > 0 else "0" code += "F" if (ival & 0x01) > 0 else "0"
ival >>= 1 ival >>= 1
return code return code
@ -167,20 +173,20 @@ class TristateBase(RcProtocol): #Baseclass for old intertechno, Brennenstuhl, ..
i = 0 i = 0
while tristateval != "": while tristateval != "":
i <<= 1 i <<= 1
if tristateval[-1] != '0': if tristateval[-1] == "F":
i |= 1 i |= 1
tristateval = tristateval[:-1] tristateval = tristateval[:-1]
return i return i
class Tristate(TristateBase): #old intertechno class Tristate(TristateBase):
def __init__(self): def __init__(self):
self._name = "tristate" self._name = "tristate"
TristateBase.__init__(self) TristateBase.__init__(self)
self.params = [PARAM_CODE] self.params = [PARAM_CODE]
def encode(self, params, timebase=None, repetitions=None): 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): def decode(self, pulsetrain):
symbols, tb, rep = self._decode_symbols(pulsetrain[0:-2]) 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(ord(params["house"][0]) - ord('A'), 4)
symbols += self._encode_int(int(params["unit"]) - 1, 2) symbols += self._encode_int(int(params["unit"]) - 1, 2)
symbols += self._encode_int(int(params["group"]) - 1, 2) symbols += self._encode_int(int(params["group"]) - 1, 2)
symbols += "0f" symbols += "0F"
symbols += self._encode_command(params["command"]) symbols += self._encode_command(params["command"])
return self._build_frame(symbols, timebase, repetitions) 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')), "house": chr(self._decode_int(symbols[:4]) + ord('A')),
"unit": self._decode_int(symbols[4:6]) + 1, "unit": self._decode_int(symbols[4:6]) + 1,
"group": self._decode_int(symbols[6:8]) + 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 }, tb, rep
class Brennenstuhl(TristateBase): #old intertechno class Brennenstuhl(TristateBase):
def __init__(self): def __init__(self):
self._name = "brennenstuhl" self._name = "brennenstuhl"
TristateBase.__init__(self) TristateBase.__init__(self)
@ -248,7 +254,7 @@ class Brennenstuhl(TristateBase): #old intertechno
"command": self._decode_command(symbols[10:12].upper()), "command": self._decode_command(symbols[10:12].upper()),
}, tb, rep }, tb, rep
class PPM1(RcProtocol): #Intertechno, Hama, ... class PPM1(RcPulse): #Intertechno, Hama, Nexa, Telldus, ...
''' '''
PDM1: Pulse Position Modulation PDM1: Pulse Position Modulation
Every bit consists of 2 shortpulses. Long distance between these pulses 2 pulses -> 1, else -> 0 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], '1': [1, 5, 1, 1],
} }
self._footer = [1, 39] self._footer = [1, 39]
RcProtocol.__init__(self) self._class = CLASS_RCSWITCH
RcPulse.__init__(self)
class Intertechno(PPM1): class Intertechno(PPM1):
def __init__(self): def __init__(self):
PPM1.__init__(self)
self._name = "intertechno" self._name = "intertechno"
self._timebase = 275
self.params = [PARAM_ID, PARAM_UNIT, PARAM_COMMAND] self.params = [PARAM_ID, PARAM_UNIT, PARAM_COMMAND]
self._commands = {"on": "1", "off": "0"} self._commands = {"on": "1", "off": "0"}
self._timebase = 275
PPM1.__init__(self)
def _encode_unit(self, unit): def _encode_unit(self, unit):
return "{:04b}".format(int(unit) - 1) return "{:04b}".format(int(unit) - 1)
@ -311,9 +318,9 @@ class Hama(Intertechno):
return 16 - int(unit, 2) 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 Wide pulse -> 1, small pulse -> 0
Frame: header, payload, footer Frame: header, payload, footer
Used by Emylo, Logilight, ... Used by Emylo, Logilight, ...
@ -327,14 +334,15 @@ class PWM1(RcProtocol):
'0': [1, 3], '0': [1, 3],
} }
self._footer = [1, 31] self._footer = [1, 31]
RcProtocol.__init__(self) self._class = CLASS_RCSWITCH
RcPulse.__init__(self)
class Logilight(PWM1): class Logilight(PWM1):
def __init__(self): def __init__(self):
PWM1.__init__(self)
self._name = "logilight" self._name = "logilight"
self.params = [PARAM_ID, PARAM_UNIT, PARAM_COMMAND] self.params = [PARAM_ID, PARAM_UNIT, PARAM_COMMAND]
self._commands = {"on": "1", "learn": "1", "off": "0"} self._commands = {"on": "1", "learn": "1", "off": "0"}
PWM1.__init__(self)
def _encode_unit(self, unit): def _encode_unit(self, unit):
res = "" res = ""
@ -373,10 +381,10 @@ class Logilight(PWM1):
class Emylo(PWM1): class Emylo(PWM1):
def __init__(self): def __init__(self):
PWM1.__init__(self)
self._name = "emylo" self._name = "emylo"
self.params = [PARAM_ID, PARAM_COMMAND] self.params = [PARAM_ID, PARAM_COMMAND]
self._commands = {'A': '0001', 'B': '0010', 'C': '0100', 'D': '1000'} self._commands = {'A': '0001', 'B': '0010', 'C': '0100', 'D': '1000'}
PWM1.__init__(self)
def encode(self, params, timebase=None, repetitions=None): def encode(self, params, timebase=None, repetitions=None):
symbols = "" symbols = ""
@ -392,7 +400,7 @@ class Emylo(PWM1):
"command": self._decode_command(symbols[-4:]) "command": self._decode_command(symbols[-4:])
}, tb, rep }, tb, rep
class FS20(RcProtocol): class FS20(RcPulse):
def __init__(self): def __init__(self):
self._name = "fs20" self._name = "fs20"
self._timebase = 200 self._timebase = 200
@ -405,7 +413,8 @@ class FS20(RcProtocol):
self._header = [2, 2] * 12 + [3, 3] self._header = [2, 2] * 12 + [3, 3]
self._footer = [1, 100] self._footer = [1, 100]
self.params = [PARAM_ID,PARAM_UNIT, PARAM_COMMAND] self.params = [PARAM_ID,PARAM_UNIT, PARAM_COMMAND]
RcProtocol.__init__(self) self._class = CLASS_RCSWITCH
RcPulse.__init__(self)
def __encode_byte(self, b): def __encode_byte(self, b):
b &= 0xFF b &= 0xFF
@ -439,7 +448,7 @@ class FS20(RcProtocol):
"command": int(symbols[40:48], 2), "command": int(symbols[40:48], 2),
}, tb, rep }, tb, rep
class Voltcraft(RcProtocol): class Voltcraft(RcPulse):
''' '''
PPM: Pulse Position Modulation PPM: Pulse Position Modulation
Pulse in middle of a symbol: 0, end of symbol: 1 Pulse in middle of a symbol: 0, end of symbol: 1
@ -458,7 +467,8 @@ class Voltcraft(RcProtocol):
self._footer = [132] self._footer = [132]
self.params = [PARAM_ID, PARAM_UNIT, PARAM_COMMAND] self.params = [PARAM_ID, PARAM_UNIT, PARAM_COMMAND]
self._commands = {"off": "000", "alloff": "100", "on": "010", "allon": "110", "dimup": "101", "dimdown": "111"} 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): def encode(self, params, timebase=None, repetitions=None):
if params["command"] in ["on", "off"]: if params["command"] in ["on", "off"]:
@ -483,27 +493,11 @@ class Voltcraft(RcProtocol):
"command": self._decode_command(symbols[14:17]) "command": self._decode_command(symbols[14:17])
}, tb, rep }, tb, rep
class PWM2(RcProtocol): class PilotaCasa(RcPulse):
''' '''
PWM2: Pulse Width Modulation Pulse Width Modulation 32 bit
Wide pulse -> 0, small pulse -> 1 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 = { __codes = {
'110001': (1, 1, 'on'), '111110': (1, 1, 'off'), '110001': (1, 1, 'on'), '111110': (1, 1, 'off'),
'011001': (1, 2, 'on'), '010001': (1, 2, 'off'), '011001': (1, 2, 'on'), '010001': (1, 2, 'off'),
@ -521,9 +515,18 @@ class PilotaCasa(PWM2):
} }
def __init__(self): def __init__(self):
PWM2.__init__(self)
self._name = "pilota" 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.params = [PARAM_ID, PARAM_GROUP, PARAM_UNIT, PARAM_COMMAND]
self._class = CLASS_RCSWITCH
RcPulse.__init__(self)
def encode(self, params, timebase=None, repetitions=None): def encode(self, params, timebase=None, repetitions=None):
symbols = '01' symbols = '01'
@ -551,36 +554,33 @@ class PilotaCasa(PWM2):
"command": c[2], "command": c[2],
}, tb, rep }, tb, rep
class PCPIR(RcProtocol): #pilota casa PIR sensor class PCPIR(TristateBase): #pilota casa PIR sensor
'''
Pilota Casa IR sensor
'''
def __init__(self): def __init__(self):
self._name = "pcpir" self._name = "pcpir"
self._timebase = 400 self.params = [PARAM_ID, PARAM_COMMAND]
self._repetitions = 5 self._timebase = 500
self._pattern = "[01]{12}" self._commands = {"off": "0", "on": "F"}
self._symbols = { TristateBase.__init__(self)
'1': [1, 3, 1, 3],
'0': [1, 3, 3, 1], def encode(self, params, timebase=None, repetitions=None):
} symbols = ""
RcProtocol.__init__(self) return self._build_frame(symbols, timebase, repetitions)
self._parser.add_argument("-c", "--code", required=True)
def decode(self, pulsetrain): def decode(self, pulsetrain):
code, tb, rep = self._decode_symbols(pulsetrain[0:-2]) symbols, tb, rep = self._decode_symbols(pulsetrain[0:-2])
if code: if symbols:
print("PCIR", symbols, pulsetrain)
return { return {
"protocol": self._name, "id": self._decode_int(symbols[5:10]),
"code": code, "unit": self._decode_int(symbols[0:5]),
"timebase": tb, "command": self._decode_command(symbols[11:12])
}, rep }, 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, Pulse Width Modulation 24 bit,
Short pulse: 0, long pulse: 1 Short pulse: 0, long pulse: 1
@ -597,7 +597,8 @@ class REVRitterShutter(RcProtocol):
} }
self._footer = [1, 85] self._footer = [1, 85]
self.params = [PARAM_ID] self.params = [PARAM_ID]
RcProtocol.__init__(self) self._class = CLASS_RCSWITCH
RcPulse.__init__(self)
def encode(self, params, timebase=None, repetitions=None): def encode(self, params, timebase=None, repetitions=None):
symbols = "{:024b}".format(int(params["id"])) symbols = "{:024b}".format(int(params["id"]))
@ -610,6 +611,91 @@ class REVRitterShutter(RcProtocol):
"id": int(symbols[0:24], 2), "id": int(symbols[0:24], 2),
}, tb, rep }, 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 = [ protocols = [
Tristate(), Tristate(),
ITTristate(), ITTristate(),
@ -618,13 +704,13 @@ protocols = [
Hama(), Hama(),
Logilight(), Logilight(),
Emylo(), Emylo(),
#PWM2(),
Voltcraft(), Voltcraft(),
#PCPIR(), PCPIR(),
#PDM1(),
FS20(), FS20(),
PilotaCasa(), PilotaCasa(),
REVRitterShutter() REVRitterShutter(),
WH2(),
WS7000(),
] ]
def get_protocol(name): def get_protocol(name):
@ -633,7 +719,6 @@ def get_protocol(name):
return p return p
return None return None
RXDATARATE = 20.0 #kbit/s RXDATARATE = 20.0 #kbit/s
class RfmPulseTRX(threading.Thread): class RfmPulseTRX(threading.Thread):
def __init__(self, module, rxcb, frequency): def __init__(self, module, rxcb, frequency):
@ -742,7 +827,7 @@ class RcTransceiver(threading.Thread):
if params: if params:
succ = True succ = True
if not rep: if not rep:
res.append({"protocol": p._name, "params": params}) res.append({"protocol": p._name, "class": p._class, "params": params})
except Exception as e: except Exception as e:
pass pass

View file

@ -1,4 +1,4 @@
#!/usr/bin/env python2.7 #!/usr/bin/env python
from raspyrfm import * from raspyrfm import *
import sys import sys

View file

@ -1,4 +1,4 @@
#!/usr/bin/env python2.7 #!/usr/bin/env python
import socket import socket
import threading import threading
@ -27,10 +27,11 @@ def rxcb(dec, train):
if len(dec) > 0: if len(dec) > 0:
payload = {"decode": dec, "raw": train} payload = {"decode": dec, "raw": train}
print(payload)
if payload is not None: if payload is not None:
print("RX", payload)
s = json.dumps(payload) + "\n"
for client in clients: for client in clients:
client.send(payload) client.send(s)
if not raspyrfm_test(args.module, RFM69): if not raspyrfm_test(args.module, RFM69):
@ -38,7 +39,6 @@ if not raspyrfm_test(args.module, RFM69):
exit() exit()
rctrx = rcprotocols.RcTransceiver(args.module, args.frequency, rxcb) rctrx = rcprotocols.RcTransceiver(args.module, args.frequency, rxcb)
lock = threading.Lock() lock = threading.Lock()
class clientthread(threading.Thread): class clientthread(threading.Thread):
@ -46,19 +46,24 @@ class clientthread(threading.Thread):
self.__socket = socket self.__socket = socket
threading.Thread.__init__(self) threading.Thread.__init__(self)
def send(self, obj): def send(self, s):
self.__socket.send(json.dumps(obj)) self.__socket.sendall(s.encode())
def run(self): def run(self):
buf = ""
while True: while True:
chunk = self.__socket.recv(1024) chunk = self.__socket.recv(32).decode()
if len(chunk) == 0: if len(chunk) == 0:
del self.__socket del self.__socket
break break
try:
#print(chunk)
lock.acquire() lock.acquire()
d = json.loads(chunk) try:
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"]) rctrx.send(d["protocol"], d["params"])
except: except:
pass pass