Files
home-assistant/appdaemon/settings/apps/climate/irgen.py
T
2019-11-29 21:19:01 +03:00

326 lines
8.4 KiB
Python

from base64 import b64encode, b64decode
import binascii
from itertools import islice
gen_raw_nec_protocols_standard = ['nec1',
'nec2',
'necx1',
'necx2']
gen_raw_nec_protocols_suffixes = ['',
'-y1',
'-y2',
'-y3',
'-f16']
gen_raw_nec_protocols = list(x + y for x in gen_raw_nec_protocols_standard
for y in gen_raw_nec_protocols_suffixes)
gen_raw_rc5_protocols = ['rc5']
gen_raw_rc6_protocols = ['rc6']
gen_raw_protocols = [*gen_raw_nec_protocols, *gen_raw_rc5_protocols, *gen_raw_rc6_protocols]
def uX_to_bin(v, x):
if(v < 0):
v += (1 << x)
return bin(v)[2:].rjust(x, '0')
def gen_raw_rc5(protocol, device, subdevice, function, toggle=0):
logical_bit = 889.0
def encode_bit(s):
if s == '1':
yield logical_bit * -1
yield logical_bit * 1
else:
yield logical_bit * 1
yield logical_bit * -1
def encode_uX(x, l):
for s in uX_to_bin(x, l):
yield from encode_bit(s)
yield from encode_bit('1') # start
if function < 64:
yield from encode_bit('1') # field (function 0-63)
else:
yield from encode_bit('0') # field (function 64-127)
yield from encode_bit(str(toggle)) # toggle
# address
yield from encode_uX(device, 5)
# command
yield from encode_uX(function % 64, 6)
# trailing silence
yield logical_bit * -100
def gen_raw_rc6(protocol, device, subdevice, function, toggle=0, mode=0):
logical_bit = 444.0
def encode_bit(s):
if s == '1':
yield logical_bit * 1
yield logical_bit * -1
else:
yield logical_bit * -1
yield logical_bit * 1
def encode_uX(x, l):
for s in uX_to_bin(x, l):
yield from encode_bit(s)
#LS
yield logical_bit * 6
yield logical_bit * -2
#SB
yield from encode_bit('1')
#Mode
yield from encode_uX(mode, 3)
#TB
if toggle:
yield logical_bit * 2
yield logical_bit * -2
else:
yield logical_bit * -2
yield logical_bit * 2
#Control
yield from encode_uX(device, 8)
#Information
yield from encode_uX(function, 8)
#Signal Free
yield logical_bit * -6
def gen_raw_nec(protocol, device, subdevice, function):
logical_bit = 562.5
protocol_base, protocol_suffix = (protocol.split('-') + [None])[:2]
def encode(value):
b = uX_to_bin(value, 8)
for s in reversed(b):
yield logical_bit # burst
if s == '1':
yield logical_bit * -3 # one is encoded by 3 length
else:
yield logical_bit * -1 # zero is encoded by 1 lengths
if protocol_base in ('nec1', 'necx1'):
yield logical_bit * 16 # leading burst
else:
yield logical_bit * 8 # leading burst
yield logical_bit * -8 # space before data
yield from encode(device)
if subdevice >= 0:
yield from encode(subdevice)
else:
yield from encode(~device)
yield from encode(function & 0xFF)
if protocol_suffix == 'y1': # Yamaha special version 1
yield from encode(function ^ 0x7F)
elif protocol_suffix == 'y2': # Yamaha special version 2
yield from encode(function ^ 0xFE)
elif protocol_suffix == 'y3': # Yamaha special version 3
yield from encode(function ^ 0x7E)
elif protocol_suffix == 'f16': # 16 bit function
yield from encode((function >> 8) & 0xFF)
else: # Standard invert
yield from encode(function ^ 0xFF)
yield logical_bit # Trailing burst
yield logical_bit * -3 # Trailing zero to separate
def gen_raw_general(protocol, device, subdevice, function, **kwargs):
if protocol.lower() in gen_raw_nec_protocols:
yield from gen_raw_nec(protocol.lower(),
int(device),
int(subdevice),
int(function))
if protocol.lower() in gen_raw_rc5_protocols:
yield from gen_raw_rc5(protocol.lower(),
int(device),
int(subdevice),
int(function))
if protocol.lower() in gen_raw_rc6_protocols:
yield from gen_raw_rc6(protocol.lower(),
int(device),
int(subdevice),
int(function))
def gen_simplified_from_raw(x):
"""
Simplify raw string.
Combine successive same sign value, drop zeros, drop leading negative
"""
value = 0
for i in x:
if i == 0:
continue
elif value == 0:
if i > 0:
value = i
else:
pass # leading negative
elif (value > 0) == (i > 0):
value += i
else:
yield value
value = i
if value != 0:
yield value
def gen_paired_from_raw(x):
"""
Create pairs of on, off
"""
sign = 1
for i in x:
if (i < 0) ^ (sign < 0):
yield 0.0
yield i
else:
yield i
sign = -sign
if sign < 0:
yield 0.0
def gen_raw_from_broadlink(data):
v = iter(data)
code = next(v)
repeat = next(v)
assert code == 0x26 # IR
length = int.from_bytes(islice(v, 2), byteorder='little')
def decode_one(x):
return round(x * 8192 / 269)
def decode_iter(x):
sign = 1
while True:
d = next(x)
if d == 0:
d = int.from_bytes(islice(x, 2), byteorder='big')
yield sign * decode_one(d)
sign = sign * -1
yield from decode_iter(islice(v, length))
def gen_raw_from_broadlink_base64(data):
yield from gen_raw_from_broadlink(b64decode(data))
def gen_broadlink_from_raw(data, repeat=0):
yield from b'\x26' # IR
yield from repeat.to_bytes(1, byteorder='big') # Repeat
def encode_one(x):
# v = abs(int(i / 32.84))
v = abs(int(x * 269 / 8192))
if v > 255:
yield from b'\x00'
yield from v.to_bytes(2, byteorder='big')
else:
yield from v.to_bytes(1, byteorder='big')
def encode_list(x):
for i in gen_simplified_from_raw(x):
yield from encode_one(i)
c = bytearray(encode_list(data))
count = len(c)
yield from count.to_bytes(2, byteorder='little')
yield from c
yield from b'\x0d'
yield from b'\x05'
# calculate total length for padding
count += 6 # header+len+trailer
count += 4 # rm.send_data() 4 byte header (not seen here)
yield from bytearray(16 - (count % 16))
def gen_broadlink_base64_from_raw(data, repeat=0):
return b64encode(bytes(gen_broadlink_from_raw(data, repeat)))
def gen_raw_from_pronto(data):
clock = 0.241246 # Pronto clock base: 1000000 / (32768 * 506 / 4)
v = iter(data)
zero = next(v)
assert zero == 0
base = next(v)
freq = 1.0 / (base * clock)
seq1_len = next(v)
seq2_len = next(v)
for _ in range(seq1_len):
yield +round(next(v) / freq, 1)
yield -round(next(v) / freq, 1)
for _ in range(seq2_len):
yield +round(next(v) / freq, 1)
yield -round(next(v) / freq, 1)
def gen_pronto_from_raw_int(seq1, seq2, base=None, freq=None):
clock = 0.241246 # Pronto clock base: 1000000 / (32768 * 506 / 4)
if freq is None:
if base is None:
freq = 0.040
else:
freq = 1.0 / (base * clock)
if base is None:
base = int(1 / (freq * clock))
yield 0
yield base
def fixup(x):
return list(gen_paired_from_raw(gen_simplified_from_raw(x)))
#return list(gen_paired_from_raw((x)))
simple1 = fixup(seq1)
simple2 = fixup(seq2)
yield int(len(simple1)/2) # sequence 1
yield int(len(simple2)/2) # sequence 2
for x in simple1:
yield int(abs(x) * freq)
for x in simple2:
yield int(abs(x) * freq)
def gen_pronto_from_raw(seq1, seq2, base=None, freq=None):
data = gen_pronto_from_raw_int(seq1, seq2, base, freq)
for value in data:
yield "{0:0{1}x}".format(value,4)