# encoder.py 27/03/2016 D.J.Whale # # payload encoder for use with OOK payloads ALL_SOCKETS = 0 # The preamble is now stored in the payload, # this is more predictable than using the radio sync feature PREAMBLE = [0x80, 0x00, 0x00, 0x00] # This generates a 20*4 bit address i.e. 10 bytes # The number generated is always the same # This is the random 'Energenie address prefix' # The switch number is encoded in the payload # 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) #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 DEFAULT_ADDR = 0x6C6C6 # 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) DEFAULT_ADDR_ENC = [0x8e, 0xe8, 0xee, 0x88, 0x8e, 0xe8, 0xee, 0x88, 0x8e, 0xe8] # D0=high, D1=high, D2-high, D3=high (S1 on) sent as:(D0D1D2D3) # 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 SW1_ON_ENC = [0xEE, 0xEE] # 1111 sent as 1111 # 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 SW1_OFF_ENC = [0xEE, 0xE8] # 1110 sent as 0111 def ashex(payload): line = "" for b in payload: line += str(hex(b)) + " " return line #TODO: encode_relay_msg def build_relay_msg(relayState=False): """Temporary test code to prove we can turn the relay on or off""" payload = PREAMBLE #TODO: + DEFAULT_ADDR_ENC ?? if relayState: # ON payload += SW1_ON_ENC else: # OFF payload += SW1_OFF_ENC return payload #TODO: encode_test_message def build_test_message(pattern): """build a test message for a D3D2D1D0 control patter""" payload = PREAMBLE + DEFAULT_ADDR_ENC pattern &= 0x0F control = encode_bits(pattern, 4) payload += control return payload #TODO: encode_switch_msg 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: house_address = DEFAULT_ADDR payload = [] + PREAMBLE payload += encode_bits((house_address & 0x0F0000) >> 16, 4) payload += encode_bits((house_address & 0x00FF00) >> 8, 8) payload += encode_bits((house_address & 0x0000FF), 8) # Coded as per the (working) C code, as it is transmitted D0D1D2D3: # D 0123 # b 3210 # 0000 UNUSED 0 # 0001 UNUSED 1 # 0010 socket 4 off 2 # 0011 socket 4 on 3 # 0100 UNUSED 4 # 0101 UNUSED 5 # 0110 socket 2 off 6 # 0111 socket 2 on 7 # 1000 UNUSED 8 # 1001 UNUSED 9 # 1010 socket 3 off A # 1011 socket 3 on B # 1100 all off C # 1101 all on D # 1110 socket 1 off E # 1111 socket 1 on F if not state: # OFF bits = 0x00 else: # ON bits = 0x01 if device_address == ALL_SOCKETS: bits |= 0x0C # ALL elif device_address == 1: bits |= 0x0E elif device_address == 2: bits |= 0x06 elif device_address == 3: bits |= 0x0A elif device_address == 4: bits |= 0x02 payload += encode_bits(bits, 4) #print("encoded as:%s" % ashex(payload)) return payload #TODO: decode_switch_msg 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(int(number/2)): bits = (data >> shift) & 0x03 #print(" shift %d bits %d" % (shift, bits)) encoded.append(ENCODER[bits]) shift -= 2 #print(" returns:%s" % ashex(encoded)) return encoded #TODO: decode_bytes #TODO: decode_bits #TODO: decode_command # 0, False (all off) # 0, True (all on) # 1, False (1 off) # 1, True (1 on) # 2, False (2 off) # 2, True (2 on) # 3, False (3 off) # 3, True (3 on) # 4, False (4 off) # 4, True (4 on) # UNKNOWN (6 of the other patterns, that are not recognised) # END