diff --git a/src/energenie/encoder.py b/src/energenie/encoder.py new file mode 100644 index 0000000..f5897a0 --- /dev/null +++ b/src/energenie/encoder.py @@ -0,0 +1,134 @@ +# encoder.py 27/03/2016 D.J.Whale +# +# payload encoder for use with OOK payloads + +ALL_SOCKETS = 0 + +def build_relay_msg(relayState=False): + """Temporary test code to prove we can turn the relay on or off""" + + # This generates a 20*4 bit address i.e. 10 bytes + # The number generated is always the same + # Presumably this is the random 'Energenie address prefix' + # The switch number is encoded in the payload + + # Looks like: 0000 00BA gets encoded as: + # 128 64 32 16 8 4 2 1 + # 1 B B 0 1 A A 0 + + #payload = [] + #for i in range(10): + # j = i + 5 + # payload.append(8 + (j&1) * 6 + 128 + (j&2) * 48) + #dumpPayloadAsHex(payload) + # + # 5 6 7 8 9 10 11 12 13 14 + # 1(01) 1(10) 1(11) 0(00) 0(01) 0(10) 0(11) 1(00) 1(01) 1(10) + payload = [0x8e, 0xe8, 0xee, 0x88, 0x8e, 0xe8, 0xee, 0x88, 0x8e, 0xe8] + + #TODO: This is taken from the C code, it might be wrong + #(the D bit order seems reversed compared to the pdf spec) + if relayState: # ON + # D0=high, D1=high, D2-high, D3=high (S1 on) + # 128 64 32 16 8 4 2 1 128 64 32 16 8 4 2 1 + # 1 B B 0 1 A A 0 1 B B 0 1 A A 0 + # 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 + payload += [0xEE, 0xEE] # 1111 + + else: # OFF + # D0=high, D1=high, D2=high, D3=low (S1 off) + # 128 64 32 16 8 4 2 1 128 64 32 16 8 4 2 1 + # 1 B B 0 1 A A 0 1 B B 0 1 A A 0 + # 1 1 1 0 1 1 1 0 1 1 1 0 1 0 0 0 + payload += [0xEE, 0xE8] # 1110 + + return payload + + +def build_switch_msg(state, device_address=ALL_SOCKETS, house_address=None): + """Build a message to turn a switch on or off""" + #print("build: state:%s, device:%d, house:%s" % (str(state), device_address, str(house_address))) + + if house_address == None: + #this is just a fixed address generator, from the C code + #payload = [] + #for i in range(10): + # j = i + 5 + # payload.append(8 + (j&1) * 6 + 128 + (j&2) * 48) + #dumpPayloadAsHex(payload) + # binary = 0110 1100 0110 1100 0110 + # hex = 6 C 6 C 6 + house_address = 0x6C6C6 + + payload = encode_bits((house_address & 0x0F0000) >> 16, 4) + payload += encode_bits((house_address & 0x00FF00) >> 8, 8) + payload += encode_bits((house_address & 0x0000FF), 8) + + #TODO: D3210 are the other way round in the message?? + #This is correct as presented by the PDF from Energenie though. + # Turn switch request into a 4 bit switch command, and add to payload + # D 3210 + # 0000 UNUSED + # 0001 UNUSED + # 0010 UNUSED + # 0011 All off (3) + # 0100 socket 4 off (4) + # 0101 socket 3 off (5) + # 0110 socket 2 off (6) + # 0111 socket 1 off (7) + # 1000 UNUSED + # 1101 UNUSED + # 1110 UNUSED + # 1011 All on (3) + # 1100 socket 4 on (4) + # 1101 socket 3 on (5) + # 1110 socket 2 on (6) + # 1111 socket 1 on (7) + + if not state: # OFF + bits = 0x00 + else: # ON + bits = 0x08 + + if device_address == ALL_SOCKETS: + bits |= 0x03 # ALL + else: + bits += 7-((device_address-1) & 0x03) + + payload += encode_bits(bits, 4) + return payload + + +def encode_bytes(data): + """Turn a list of bytes into a modulated pattern equivalent""" + #print("modulate_bytes: %s" % ashex(data)) + payload = [] + for b in data: + payload += encode_bits(b, 8) + #print(" returns: %s" % ashex(payload)) + return payload + + +ENCODER = [0x88, 0x8E, 0xE8, 0xEE] + +def encode_bits(data, number): + """Turn bits into n bytes of modulation patterns""" + # 0000 00BA gets encoded as: + # 128 64 32 16 8 4 2 1 + # 1 B B 0 1 A A 0 + # i.e. a 0 is a short pulse, a 1 is a long pulse + #print("modulate_bits %s (%s)" % (ashex(data), str(number))) + + shift = number-2 + encoded = [] + for i in range(number/2): + bits = (data >> shift) & 0x03 + #print(" shift %d bits %d" % (shift, bits)) + encoded.append(ENCODER[bits]) + shift -= 2 + #print(" returns:%s" % ashex(modulated)) + return encoded + + +# END + diff --git a/src/energenie/modulator.py b/src/energenie/modulator.py deleted file mode 100644 index bd6b96e..0000000 --- a/src/energenie/modulator.py +++ /dev/null @@ -1,91 +0,0 @@ -# modulator.py 27/03/2016 D.J.Whale -# -# modulator for use with OOK payloads - -ALL_SOCKETS = 0 - -def build_switch_msg(state, device_address=ALL_SOCKETS, house_address=None): - """Build a message to turn a switch on or off""" - #print("build: state:%s, device:%d, house:%s" % (str(state), device_address, str(house_address))) - - if house_address == None: - #this is just a fixed address generator, from the C code - #payload = [] - #for i in range(10): - # j = i + 5 - # payload.append(8 + (j&1) * 6 + 128 + (j&2) * 48) - #dumpPayloadAsHex(payload) - # binary = 0110 1100 0110 1100 0110 - # hex = 6 C 6 C 6 - house_address = 0x6C6C6 - - payload = modulate_bits((house_address & 0x0F0000) >> 16, 4) - payload += modulate_bits((house_address & 0x00FF00) >> 8, 8) - payload += modulate_bits((house_address & 0x0000FF), 8) - - # Turn switch request into a 4 bit switch command, and add to payload - # D 3210 - # 0000 UNUSED - # 0001 UNUSED - # 0010 UNUSED - # 0011 All off (3) - # 0100 socket 4 off (4) - # 0101 socket 3 off (5) - # 0110 socket 2 off (6) - # 0111 socket 1 off (7) - # 1000 UNUSED - # 1101 UNUSED - # 1110 UNUSED - # 1011 All on (3) - # 1100 socket 4 on (4) - # 1101 socket 3 on (5) - # 1110 socket 2 on (6) - # 1111 socket 1 on (7) - - if not state: # OFF - bits = 0x00 - else: # ON - bits = 0x08 - - if device_address == ALL_SOCKETS: - bits |= 0x03 # ALL - else: - bits += 7-((device_address-1) & 0x03) - - payload += modulate_bits(bits, 4) - return payload - - -def modulate_bytes(data): - """Turn a list of bytes into a modulated pattern equivalent""" - #print("modulate_bytes: %s" % ashex(data)) - payload = [] - for b in data: - payload += modulate_bits(b, 8) - #print(" returns: %s" % ashex(payload)) - return payload - - -MODULATOR = [0x88, 0x8E, 0xE8, 0xEE] - -def modulate_bits(data, number): - """Turn bits into n bytes of modulation patterns""" - # 0000 00BA gets encoded as: - # 128 64 32 16 8 4 2 1 - # 1 B B 0 1 A A 0 - # i.e. a 0 is a short pulse, a 1 is a long pulse - #print("modulate_bits %s (%s)" % (ashex(data), str(number))) - - shift = number-2 - modulated = [] - for i in range(number/2): - bits = (data >> shift) & 0x03 - #print(" shift %d bits %d" % (shift, bits)) - modulated.append(MODULATOR[bits]) - shift -= 2 - #print(" returns:%s" % ashex(modulated)) - return modulated - - -# END - diff --git a/src/energenie/radio.py b/src/energenie/radio.py index d47fddf..f39be83 100644 --- a/src/energenie/radio.py +++ b/src/energenie/radio.py @@ -354,48 +354,6 @@ # HRF_wait_for (ADDR_IRQFLAGS1, MASK_MODEREADY, true); // wait for ModeReady #} -def OLD_build_OOK_relay_msg(relayState=False): - """Temporary test code to prove we can turn the relay on or off""" - #This code does not live in this module, it lives in an EnergenieLegacy codec module - #also there are 4 switches, so should pass in up to 4 relayState values - - # This generates a 20*4 bit address i.e. 10 bytes - # The number generated is always the same - # Presumably this is the 'Energenie address prefix' - # The switch number is encoded in the payload - # This code looks screwy, but it is correct compared to the C code. - # It's probably doing bit encoding on the fly, manchester or sync bits or something. - # Wait until we get the OOK spec from Energenie to better document this. - - # Looks like: 0000 00BA gets encoded as: - # 128 64 32 16 8 4 2 1 - # 1 B B 0 1 A A 0 - - #payload = [] - #for i in range(10): - # j = i + 5 - # payload.append(8 + (j&1) * 6 + 128 + (j&2) * 48) - #dumpPayloadAsHex(payload) - # - # 5 6 7 8 9 10 11 12 13 14 - # 1(01) 1(10) 1(11) 0(00) 0(01) 0(10) 0(11) 1(00) 1(01) 1(10) - payload = [0x8e, 0xe8, 0xee, 0x88, 0x8e, 0xe8, 0xee, 0x88, 0x8e, 0xe8] - - if relayState: # ON - # D0=high, D1=high, D2-high, D3=high (S1 on) - # 128 64 32 16 8 4 2 1 128 64 32 16 8 4 2 1 - # 1 0 B B 1 A A 0 1 0 B B 1 A A 0 - # 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 = 10 11 10 11 - payload += [0xEE, 0xEE] - else: # OFF - # D0=high, D1=high, D2=high, D3=low (S1 off) - # 128 64 32 16 8 4 2 1 128 64 32 16 8 4 2 1 - # 1 0 B B 1 A A 0 1 0 B B 1 A A 0 - # 1 1 1 0 1 1 1 0 1 1 1 0 1 0 0 0 = 10 11 10 00 - payload += [0xEE, 0xE8] - - return payload - def HRF_send_OOK_payload(payload): """Send a payload multiple times""" diff --git a/src/energenie/test_encoder.py b/src/energenie/test_encoder.py new file mode 100644 index 0000000..927061e --- /dev/null +++ b/src/energenie/test_encoder.py @@ -0,0 +1,39 @@ +# test_encoder.py 27/03/2016 D.J.Whale +# +# Test the OOK message encoder + +import encoder + +def ashex(data): + if type(data) == list: + line = "" + for b in data: + line += str(hex(b)) + " " + return line + else: + return str(hex(data)) + + +#----- TEST APPLICATION ------------------------------------------------------- + +print("*" * 80) + +ALL_ON = encoder.build_switch_msg(True) +ALL_OFF = encoder.build_switch_msg(False) +ONE_ON = encoder.build_switch_msg(True, device_address=1) +ONE_OFF = encoder.build_switch_msg(False, device_address=1) +TWO_ON = encoder.build_switch_msg(True, device_address=2) +TWO_OFF = encoder.build_switch_msg(False, device_address=2) +THREE_ON = encoder.build_switch_msg(True, device_address=3) +THREE_OFF = encoder.build_switch_msg(False, device_address=3) +FOUR_ON = encoder.build_switch_msg(True, device_address=4) +FOUR_OFF = encoder.build_switch_msg(False, device_address=4) +MYHOUSE_ALL_ON = encoder.build_switch_msg(True, house_address=0x12345) + +tests = [ALL_ON, ALL_OFF, ONE_ON, ONE_OFF, TWO_ON, TWO_OFF, THREE_ON, THREE_OFF, FOUR_ON, FOUR_OFF, MYHOUSE_ALL_ON] + +for t in tests: + print(ashex(t)) + +# END + diff --git a/src/energenie/test_modulator.py b/src/energenie/test_modulator.py deleted file mode 100644 index 6e0d621..0000000 --- a/src/energenie/test_modulator.py +++ /dev/null @@ -1,44 +0,0 @@ -# test_modulator.py 27/03/2016 D.J.Whale -# -# Test the OOK modulator - -import modulator - -def ashex(data): - if type(data) == list: - line = "" - for b in data: - line += str(hex(b)) + " " - return line - else: - return str(hex(data)) - - -#----- TEST APPLICATION ------------------------------------------------------- - -print("*" * 80) - -ALL_ON = modulator.build_switch_msg(True) -ALL_OFF = modulator.build_switch_msg(False) - -ONE_ON = modulator.build_switch_msg(True, device_address=1) -ONE_OFF = modulator.build_switch_msg(False, device_address=1) - -TWO_ON = modulator.build_switch_msg(True, device_address=2) -TWO_OFF = modulator.build_switch_msg(False, device_address=2) - -THREE_ON = modulator.build_switch_msg(True, device_address=3) -THREE_OFF = modulator.build_switch_msg(False, device_address=3) - -FOUR_ON = modulator.build_switch_msg(True, device_address=4) -FOUR_OFF = modulator.build_switch_msg(False, device_address=4) - -MYHOUSE_ALL_ON = modulator.build_switch_msg(True, house_address=0x12345) - -tests = [ALL_ON, ALL_OFF, ONE_ON, ONE_OFF, TWO_ON, TWO_OFF, THREE_ON, THREE_OFF, FOUR_ON, FOUR_OFF, MYHOUSE_ALL_ON] - -for t in tests: - print(ashex(t)) - -# END - diff --git a/src/legacy.py b/src/legacy.py index 1c17246..848037c 100644 --- a/src/legacy.py +++ b/src/legacy.py @@ -92,8 +92,8 @@ time.sleep(2) def legacy_test(): - ON = radio.OLD_build_OOK_relay_msg(True) - OFF = radio.OLD_build_OOK_relay_msg(False) + ON = modulator.build_relay_msg(True) + OFF = modulator.build_relay_msg(False) while True: print("ON")