add pilota casa protokoll

This commit is contained in:
S. Seegel 2020-12-05 23:37:35 +01:00
parent 95d94586db
commit f5c5ac8d8c
5 changed files with 69 additions and 292 deletions

View file

@ -35,30 +35,12 @@ see https://power-switch.eu/
## 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/
## fs20tx.py ## Receive and send 433 MHz RC remote controls
controlling FS20 RX sockets
```sh
sudo ./fs20tx <housecode> <address> <command>
```
## intertechno.py
controlling remote control sockets
```sh
./rcpulse.py -p ittristate -o <HOUSECODE A-P> -g <GROUP 1-4> -u <CHANNEL 1-4> -s <0|1> #control old intertechno sockets
./rcpulse.py -p ittristate -c <12 symbols tristate code> #control old intertechno sockets
rcpulse <26 bit address 0|1> <1 goup bit 0|1> <4 bit unit 0|1> on|off #control intertechno self learning
rcpulse <32 bit code 0|1> #control intertechno and compatible (HAMA, REV)
rcpulse <5 DIP 0|1> <channel 1-4> on|off #control Brennenstuhl RC1000
usage example:
./rcpulse.py -p ittristate -o A -g 1 -u 1 -s 1
./rcpulse.py -p ittristate -c 0000FFFF0FFF
./rcpulse 11110000111100001111000010 0 1110 on
./rcpulse 11110000111100001111000010010000
```
## Receive 433 MHz RC remote controls
```sh ```sh
./rcpulse.py ./rcpulse.py
./rcpulse.py -p intertechno -i 47612 -u 1 -a on
./rcpulse.py -p logilight -i 76123 -u 1 -a on
./rcpulse.py -p pilota -i 1234 -g 1 -u 1 -a on
``` ```
## Receive 868 MHz ELV FS20 RC remote controls ## Receive 868 MHz ELV FS20 RC remote controls

View file

@ -1,178 +0,0 @@
#!/usr/bin/env python2.7
import re
PROTOCOL = "FS20"
def __parse_byte(bits):
i = int(bits, 2)
cnt = 0
tmp = i
while tmp > 0:
cnt += 1
tmp &= tmp - 1
if (cnt & 1) == 0:
return i>>1
else:
return -1
def Decode(pulses):
if len(pulses) != 118:
print(len(pulses), pulses)
return
sym = ""
s = 0
for p in pulses:
if (p >= 300) and (p <= 500):
sym += 's'
s += p
elif (p > 500) and (p <= 750):
sym += 'l'
s += p
else:
sym += '?'
bits = ""
for i in range(59):
if sym[:2] == 'ss':
bits += "0"
elif sym[:2] == "ll":
bits += "1"
else:
bits +="?"
sym = sym[2:]
print(bits)
#check for sync sequence
if bits[:13] != "0000000000001":
return
bits = bits[13:] #strip off sync sequence
by = []
while len(bits) >= 9:
by.append(__parse_byte(bits[:9]))
bits = bits[9:]
#check checksum
cs = 6
for i in range(len(by) - 1):
cs += by[i]
cs = by[-1:][0] - (cs & 0xff)
if (cs > 2) or (cs < 0):
return
ret = {
"protocol": PROTOCOL,
"housecode": "{:04X}".format((by[0] << 8) | by[1]),
"address": "{:02X}".format(by[2]),
"command": "{:02X}".format(by[3]) if len(by) == 5 else "{:04X}".format(by[3] << 8 | by[4])
}
print(ret)
return
return ("fs20", bits, int(round(100 / (12.0 * 8 + 1))))
def Encode(args):
da = []
bp = [0]
bv = [0]
def add_pulse(val, length):
for i in range(length):
bp[0] += 1
bv[0] <<= 1
bv[0] |= val
if bp[0] == 8:
da.append(bv[0])
bv[0] = 0
bp[0] = 0
def add_bit(b):
if b == 0:
add_pulse(1, 2)
add_pulse(0, 2)
else:
add_pulse(1, 3)
add_pulse(0, 3)
def add_byte(by):
par = 0
mask = 0x80
while (mask):
add_bit(by & mask)
par >>= 1
par ^= (by & mask)
mask >>= 1
add_bit(par)
#add sync pattern
for i in range(12):
add_bit(0)
add_bit(1)
hc = int(args[0], 16)
adr = int(args[1], 16)
cmd = int(args[2], 16)
#calculate checksum
q = (6 + (hc >> 8) + (hc & 0xFF) + adr + (cmd >> 8) + (cmd & 0xFF)) & 0xff
#add housecode
add_byte(hc >> 8)
add_byte(hc & 0xFF)
#add address
add_byte(adr)
#add command
add_byte(cmd)
#add checksum
add_byte(q)
#add EOT
add_bit(0)
add_pulse(0, 33)
if bp[0] > 0:
add_pulse(0, 8-bp[0])
return (da, 3, 200)
code = ' '.join(args)
if re.match("^[01Ff]{12}$", code):
data = []
for c in code:
if c == '0':
data.append(0x88)
elif c == '1':
data.append(0xEE)
elif c in ['F', 'f']:
data.append(0x8E)
data += [0x80, 0x00, 0x00, 0x00] #sync
return (data, 5, 360)
elif re.match('^[A-P] [1-4] [1-4] (on|off)$', code):
g = re.match('^([A-P]) ([1-4]) ([1-4]) (on|off)$', code).groups()
tristate = ""
tristate += encodeBits(ord(g[0]) - ord('A'), 4) #housecode
tristate += encodeBits(ord(g[2]) - 1, 2) #channel
tristate += encodeBits(ord(g[1]) - 1, 2) #group
tristate += "0F"
tristate += 'FF' if g[3] == 'on' else 'F0'
return Encode([tristate])
elif re.match('^([01]{5}) ([1-4]) (on|off)$', code): #Brennenstuhl
g = re.match('^([01]{5}) ([1-4]) (on|off)$', code).groups()
tristate = ""
for c in g[0]:
tristate += '0' if c == '1' else 'F'
for i in range(4):
tristate += '0' if int(g[1]) - 1 == i else 'F'
tristate += 'F'
tristate += '0F' if g[2] == 'on' else 'F0'
return Encode([tristate])
elif re.match('^[1-4] [1-4] (on|off)$', code):
g = re.match('^([1-4]) ([1-4]) (on|off)$', code).groups()
tristate = ""
for i in range(4):
tristate += "0" if int(g[0]) - 1 == i else "F"
for i in range(4):
tristate += "0" if int(g[1]) - 1 == i else "F"
tristate += "FFF"
tristate += 'F' if g[2] == 'on' else '0'
return Encode([tristate])

View file

@ -4,6 +4,8 @@ from raspyrfm import *
import threading import threading
import time import time
PARAM_ID = ('i', 'id')
class RcProtocol: class RcProtocol:
def __init__(self): def __init__(self):
self.__numbits = 0 self.__numbits = 0
@ -225,7 +227,7 @@ class Intertechno(PPM1):
self._name = "intertechno" self._name = "intertechno"
self._timebase = 275 self._timebase = 275
self.params = [ self.params = [
('i', 'id'), PARAM_ID,
('u', 'unit'), ('u', 'unit'),
('a', 'command'), ('a', 'command'),
] ]
@ -272,7 +274,7 @@ class PWM1(RcProtocol):
PWM1: Pulse Width Modulation PWM1: Pulse Width Modulation
Wide pulse -> 1, small pulse -> 0 Wide pulse -> 1, small pulse -> 0
Frame: header, payload, footer Frame: header, payload, footer
Used by Intertechno self learning, Hama, ... Used by Emylo, Logilight, ...
''' '''
def __init__(self): def __init__(self):
self._timebase = 300 self._timebase = 300
@ -290,7 +292,7 @@ class Logilight(PWM1):
PWM1.__init__(self) PWM1.__init__(self)
self._name = "logilight" self._name = "logilight"
self.params = [ self.params = [
('i', 'id'), PARAM_ID,
('u', 'unit'), ('u', 'unit'),
('a', 'command'), ('a', 'command'),
] ]
@ -336,7 +338,7 @@ class Emylo(PWM1):
PWM1.__init__(self) PWM1.__init__(self)
self._name = "emylo" self._name = "emylo"
self.params = [ self.params = [
('i', 'id'), PARAM_ID,
('k', 'key'), ('k', 'key'),
] ]
self.__keys = {'A': '0001', 'B': '0010', 'C': '0100', 'D': '1000'} self.__keys = {'A': '0001', 'B': '0010', 'C': '0100', 'D': '1000'}
@ -379,7 +381,7 @@ 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 = [ self.params = [
('i', 'id'), PARAM_ID,
('u', 'unit'), ('u', 'unit'),
('a', 'command') ('a', 'command')
] ]
@ -437,7 +439,7 @@ class Voltcraft(RcProtocol):
self._header = [1] self._header = [1]
self._footer = [132] self._footer = [132]
self.params = [ self.params = [
('i', 'id'), PARAM_ID,
('u', 'unit'), ('u', 'unit'),
('a', 'command') ('a', 'command')
] ]
@ -483,7 +485,7 @@ class PWM2(RcProtocol):
def __init__(self): def __init__(self):
self._name = "pwm2" self._name = "pwm2"
self._timebase = 600 self._timebase = 600
self._repetitions = 6 self._repetitions = 10
self._pattern = "[01]{32}" self._pattern = "[01]{32}"
self._symbols = { self._symbols = {
'1': [1, 2], '1': [1, 2],
@ -495,6 +497,10 @@ class PWM2(RcProtocol):
] ]
RcProtocol.__init__(self) RcProtocol.__init__(self)
def encode(self, params, timebase=None, repetitions=None):
symbols = params["code"]
return self._build_frame(symbols, timebase, repetitions)
def decode(self, pulsetrain): def decode(self, pulsetrain):
symbols, tb, rep = self._decode_symbols(pulsetrain[:-2]) symbols, tb, rep = self._decode_symbols(pulsetrain[:-2])
@ -511,10 +517,58 @@ class PWM2(RcProtocol):
"timebase": tb, "timebase": tb,
}, rep }, rep
class PilotaCasa(PWM2):
__codes = {
'110001': (1, 1, 'on'), '111110': (1, 1, 'off'),
'011001': (1, 2, 'on'), '010001': (1, 2, 'off'),
'101001': (1, 3, 'on'), '100001': (1, 3, 'off'),
'111010': (2, 1, 'on'), '110010': (2, 1, 'off'),
'010110': (2, 2, 'on'), '011010': (2, 2, 'off'),
'100110': (2, 3, 'on'), '101010': (2, 3, 'off'),
'110111': (3, 1, 'on'), '111011': (3, 1, 'off'),
'011111': (3, 2, 'on'), '010111': (3, 2, 'off'),
'101111': (3, 3, 'on'), '100111': (3, 3, 'off'),
'111101': (4, 1, 'on'), '110101': (4, 1, 'off'),
'010011': (4, 2, 'on'), '011101': (4, 2, 'off'),
'100011': (4, 3, 'on'), '101101': (4, 3, 'off'),
}
def __init__(self):
PWM2.__init__(self)
self._name = "pilota"
self.params = [
PARAM_ID,
('g', 'group'),
('u', 'unit'),
('a', 'command')
]
def encode(self, params, timebase=None, repetitions=None): def encode(self, params, timebase=None, repetitions=None):
symbols = params["code"] symbols = '01'
u = None
for k, v in self.__codes.items():
if v[0] == int(params["group"]) and v[1] == int(params["unit"]) and v[2] == params["command"]:
u = k
break
symbols += u
symbols += "{:016b}".format(int(params["id"]))[::-1]
symbols += "11111111"
print(symbols)
return self._build_frame(symbols, timebase, repetitions) return self._build_frame(symbols, timebase, repetitions)
def decode(self, pulsetrain):
symbols, tb, rep = self._decode_symbols(pulsetrain[:-2])
if symbols and (symbols[2:8] in self.__codes):
c = self.__codes[symbols[2:8]]
params = {
"id": int(symbols[8:24][::-1], 2),
"group": c[0],
"unit": c[1],
"command": c[2],
}
return self._name, params, tb, rep
class PCPIR(RcProtocol): #pilota casa PIR sensor class PCPIR(RcProtocol): #pilota casa PIR sensor
def __init__(self): def __init__(self):
self._name = "pcpir" self._name = "pcpir"
@ -551,12 +605,13 @@ protocols = [
Hama(), Hama(),
Logilight(), Logilight(),
Emylo(), Emylo(),
PWM2(), #PWM2(),
Voltcraft(), Voltcraft(),
#PDM32(), #PDM32(),
#PCPIR(), #PCPIR(),
#PDM1(), #PDM1(),
FS20(), FS20(),
PilotaCasa()
] ]
def get_protocol(name): def get_protocol(name):

1
apps/rfmnodered.py → apps/rcpulsegw.py Executable file → Normal file
View file

@ -40,6 +40,7 @@ class clientthread(threading.Thread):
del self.__socket del self.__socket
break break
try: try:
print(chunk)
lock.acquire() lock.acquire()
d = json.loads(chunk) d = json.loads(chunk)
rctrx.send(d["protocol"], d["params"]) rctrx.send(d["protocol"], d["params"])

View file

@ -1,83 +0,0 @@
#!/usr/bin/env python2.7
from raspyrfm import *
import sys
import time
rfm = RaspyRFM(2, RFM69) #when using the RaspyRFM twin
#elif Rfm69.Test(0):
# rfm = Rfm69() #when using a single single 868 MHz RaspyRFM
#else:
# print "No RFM69 module found!"
# exit()
rfm.set_params(
Freq = 868.350,
Datarate = 5.0,
TxPower = -10,
ModulationType = rfm69.OOK,
SyncPattern = [0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x38],
Preamble = 0
)
data = []
bitcnt = 0
def AddBit(bit):
global data
global bitcnt
if bit:
if ((len(data) * 8) - bitcnt) < 6:
data.append(0)
data[bitcnt / 8] |= 0xE0 >> (bitcnt % 8)
if (bitcnt % 8) > 2:
data[(bitcnt / 8) + 1] |= (0xE0 << (8 - (bitcnt % 8))) & 0xFF
bitcnt += 6
else:
if ((len(data) * 8) - bitcnt) < 4:
data.append(0)
data[bitcnt / 8] |= 0xC0 >> (bitcnt % 8)
if (bitcnt % 8) > 4:
data[(bitcnt / 8) + 1] |= (0xC0 << (8 - (bitcnt % 8))) & 0xFF
bitcnt += 4
def AddByte(b):
mask = 0x80
while (mask):
AddBit(b & mask)
mask >>= 1
cnt = 0
while b:
cnt += 1
b &= b - 1
AddBit(cnt & 1)
def MakeFS20Frame(hc, adr, cmd):
q = 0
AddByte(hc >> 8)
AddByte(hc & 0xFF)
q += hc >> 8
q += hc & 0xFF
AddByte(adr)
q += adr
if (cmd > 0xFF):
AddByte(cmd >> 8)
q += cmd >> 8
AddByte(cmd & 0xFF)
q += cmd & 0xFF
q += 6
AddByte(q & 0xFF)
AddBit(0)
data = []
bitcnt = 0
MakeFS20Frame(int(sys.argv[1], 0), int(sys.argv[2], 0), int(sys.argv[3], 0))
print(data)
for x in range(3):
rfm.send_packet(data)