add pilota casa protokoll
This commit is contained in:
parent
95d94586db
commit
f5c5ac8d8c
5 changed files with 69 additions and 292 deletions
26
README.md
26
README.md
|
@ -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
|
||||||
|
|
178
apps/fs20.py
178
apps/fs20.py
|
@ -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])
|
|
|
@ -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
1
apps/rfmnodered.py → apps/rcpulsegw.py
Executable file → Normal 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"])
|
83
fs20tx.py
83
fs20tx.py
|
@ -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)
|
|
Loading…
Reference in a new issue