Closed syssi closed 6 years ago
I censored the ip, mac, and token, hope that is okay (Also added a few more commands):
$ mirobo discover
INFO:miio.discovery:Discovering devices with mDNS, press any key to quit...
INFO:miio.discovery:Found a supported 'ChuangmiIr' at [ip] - token: [token]
$ mirobo --ip [ip] --token [token] info
chuangmi.ir.v2 v1.2.4_38 ([MAC]) @ [ip] - token: [token]
Valid learn slot:
$ mirobo --ip [ip] --token [token] raw_command miIO.ir_learn '{"key": "1"}'
Sending cmd miIO.ir_learn with params {'key': '1'}
0
Invalid learn slot:
$ mirobo --ip [ip] --token [token] raw_command miIO.ir_learn '{"key": "-1"}'
Sending cmd miIO.ir_learn with params {'key': '-1'}
0
No command learned on the slot (It seems to forget old commands after some period of time):
$ mirobo --ip [ip] --token [token] raw_command miIO.ir_read '{"key": "1"}'
Sending cmd miIO.ir_read with params {'key': '1'}
{'error': {'code': -5002, 'message': 'no code for this key'}, 'id': 5}
Learned some random remote command:
$ mirobo --ip [ip] --token [token] raw_command miIO.ir_read '{"key": "1"}'
{'key': '1', 'code': 'Z6WPAasBAAA3BQAA4QYAAJMNAAAwJAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjABAAAAAAAAAAAAAAABAAAAAAAAAAEAAQAAAAAAAAAAAQABAQEBAAABAAEBAQAAAQQCMAEAAAAAAAAAAAAAAAEAAAAAAAAAAQABAAAAAAAAAAABAAEBAQEAAAEAAQEBAAABBAIwAQAAAAAAAAAAAAAAAQAAAAAAAAABAAEAAAAAAAAAAAEAAQEBAQAAAQABAQEAAAEEAjABAAAAAAAAAAAAAAABAAAAAAAAAAEAAQAAAAAAAAAAAQABAQEBAAABAAEBAQAAAQAA=='}
$ mirobo --ip [ip] --token [token] raw_command miIO.ir_play '{"freq": 38400, "code": "Z6WPAasBAAA3BQAA4QYAAJMNAAAwJAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjABAAAAAAAAAAAAAAABAAAAAAAAAAEAAQAAAAAAAAAAAQABAQEBAAABAAEBAQAAAQQCMAEAAAAAAAAAAAAAAAEAAAAAAAAAAQABAAAAAAAAAAABAAEBAQEAAAEAAQEBAAABBAIwAQAAAAAAAAAAAAAAAQAAAAAAAAABAAEAAAAAAAAAAAEAAQEBAQAAAQABAQEAAAEEAjABAAAAAAAAAAAAAAABAAAAAAAAAAEAAQAAAAAAAAAAAQABAQEBAAABAAEBAQAAAQAA=="}'
Sending cmd miIO.ir_play with params {'freq': 38400, 'code': 'Z6WPAasBAAA3BQAA4QYAAJMNAAAwJAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjABAAAAAAAAAAAAAAABAAAAAAAAAAEAAQAAAAAAAAAAAQABAQEBAAABAAEBAQAAAQQCMAEAAAAAAAAAAAAAAAEAAAAAAAAAAQABAAAAAAAAAAABAAEBAQEAAAEAAQEBAAABBAIwAQAAAAAAAAAAAAAAAQAAAAAAAAABAAEAAAAAAAAAAAEAAQEBAQAAAQABAQEAAAEEAjABAAAAAAAAAAAAAAABAAAAAAAAAAEAAQAAAAAAAAAAAQABAQEBAAABAAEBAQAAAQAA=='}
0
Sending learn and allow timeout:
$ mirobo --ip [ip] --token [token] raw_command miIO.ir_read '{"key": "1"}'
Sending cmd miIO.ir_read with params {'key': '1'}
{'error': {'code': -5003, 'message': 'learn timeout'}, 'id': 17}
[ip] is the ip of the device, [token] is a valid token for the device, [MAC] is the mac of the device.
Misc things:
'id': int
seem to increase for each request but is only shown in 'error'
responses.If there is anything else you need just ask :-)
Thanks for your input! It should be enough to implement some tests for the device.
Also small thing (That is also in my PR for hass):
$ mirobo --ip [ip] --token [wrong token correct length] raw_command miIO.ir_learn '{"key": "1"}'
Sending cmd miIO.ir_learn with params {'key': '1'}
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/construct/core.py", line 1222, in _parse
return self.subcon._parse(stream, context, path)
File "/usr/local/lib/python3.6/site-packages/construct/core.py", line 2038, in _parse
obj = self.cases.get(key, self.default)._parse(stream, context, path)
File "/usr/local/lib/python3.6/site-packages/construct/core.py", line 2541, in _parse
hash2 if not isinstance(hash2,bytes) else hexlify(hash2), ))
construct.core.ChecksumError: wrong checksum, read b'ffffffffffffffffffffffffffffffff', computed b'abd26cc135d1e2faee21b65b35167929'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/bin/mirobo", line 11, in <module>
sys.exit(cli())
File "/usr/local/lib/python3.6/site-packages/click/core.py", line 722, in __call__
return self.main(*args, **kwargs)
File "/usr/local/lib/python3.6/site-packages/click/core.py", line 697, in main
rv = self.invoke(ctx)
File "/usr/local/lib/python3.6/site-packages/click/core.py", line 1066, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/usr/local/lib/python3.6/site-packages/click/core.py", line 895, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/usr/local/lib/python3.6/site-packages/click/core.py", line 535, in invoke
return callback(*args, **kwargs)
File "/usr/local/lib/python3.6/site-packages/click/decorators.py", line 64, in new_func
return ctx.invoke(f, obj, *args[1:], **kwargs)
File "/usr/local/lib/python3.6/site-packages/click/core.py", line 535, in invoke
return callback(*args, **kwargs)
File "/usr/local/lib/python3.6/site-packages/miio/vacuum_cli.py", line 517, in raw_command
click.echo(vac.raw_command(cmd, params))
File "/usr/local/lib/python3.6/site-packages/miio/vacuum.py", line 270, in raw_command
return self.send(cmd, params)
File "/usr/local/lib/python3.6/site-packages/miio/device.py", line 233, in send
m = Message.parse(data, ctx)
File "/usr/local/lib/python3.6/site-packages/construct/core.py", line 156, in parse
return self.parse_stream(BytesIO(data), context, **kw)
File "/usr/local/lib/python3.6/site-packages/construct/core.py", line 169, in parse_stream
return self._parse(stream, context2, "(parsing)")
File "/usr/local/lib/python3.6/site-packages/construct/core.py", line 874, in _parse
subobj = sc._parse(stream, context, path)
File "/usr/local/lib/python3.6/site-packages/construct/core.py", line 1226, in _parse
raise e.__class__("%s\n %s" % (e, path))
construct.core.ChecksumError: wrong checksum, read b'ffffffffffffffffffffffffffffffff', computed b'abd26cc135d1e2faee21b65b35167929'
(parsing) -> checksum
This is the response I get from using an invalid token, where I replaced a single int with another int. Not sure if this is something you can look into?
Also, the 'code' length can differ, these are all the codes that I have captured until now as you can see, the "prosonic_power" is 144 chars while the others are 140:
prosonic_power:
command:
- "Z6VPAAUCAABgAgAAxQYAAOUIAACUEQAAqyIAADSeAABwdQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFEBAQEBAQEBAgICAgICAgEBAgECAQEBAQIBAgECAgICBgNXA1cDUA"
prosonic_sleep:
command:
- "Z6VHACMCAABCAgAAqAYAAMkIAAB3EQAAyyIAANCdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFEBAQEBAQEBAgICAgICAgECAQICAQECAQECAQECAgECBgNQA="
prosonic_vol_up:
command:
- 'Z6VHAAUCAABhAgAAxQYAAOQIAACUEQAArCIAADSeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFEBAQEBAQEBAgICAgICAgEBAgICAgEBAQIBAQEBAgICBgNQA='
prosonic_vol_down:
command:
- 'Z6VHAAQCAABhAgAAxQYAAOYIAACTEQAArCIAADSeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFEBAQEBAQEBAgICAgICAgECAgICAgECAQEBAQEBAgECBgNQA='
prosonic_vol_mute:
command:
- 'Z6VHAB8CAABGAgAAqwYAAMsIAAB5EQAAxiIAANCdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFEBAQEBAQEBAgICAgICAgEBAQEBAgECAQICAgIBAgECBgNQA='
prosonic_channel_up:
command:
- 'Z6VHAAQCAABiAgAAxgYAAOUIAACWEQAAqiIAADSeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFEBAQEBAQEBAgICAgICAgECAgICAgEBAQEBAQEBAgICBgNQA='
prosonic_channel_down:
command:
- 'Z6VHAAQCAABhAgAAxgYAAOUIAACVEQAArCIAADSeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFEBAQEBAQEBAgICAgICAgEBAQICAgECAQICAQEBAgECBgNQA='
Also I just captured the 'prosonic_power' command again: Z6VPACwCAACpBgAAyAgAAHYRAADHIgAA0J0AAHB1AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0AAAAAAAAAAAQEBAQEBAQAAAQABAAAAAAEAAQABAQEBBQJGAkYCQA
which differes from the one in my config, both works so it would seem like some extra information is encoded in those.
Just a couple of comments:
The 'id': int seem to increase for each request but is only shown in 'error' responses.
This is just because we return just the "result" if it is available, otherwise the whole message.
The device seems to reset by itself after some period of time, resetting the id and forgetting any learned commands.
This is a bit worrying, doesn't that render the device completely useless? Should those be cached and refreshed then periodically?
File "/usr/local/lib/python3.6/site-packages/miio/device.py", line 233, in send m = Message.parse(data, ctx) <snip> construct.core.ChecksumError: wrong checksum, read b'ffffffffffffffffffffffffffffffff', computed > b'abd26cc135d1e2faee21b65b35167929' (parsing) -> checksum
I think we should catch ChecksumErrors here and wrap them around ChecksumError(DeviceException)
. Something like:
try:
m = Message.parse(data, ctx)
except construct.core.ChecksumError as ex:
raise ChecksumError("Invalid checksum") from ex
while at it I think we should wrap returned messages containing an error to DeviceError
or similar (also based on DeviceException). The homeassistant platform can then easily just catch DeviceException
s in general and handle them accordingly.
This is a bit worrying, doesn't that render the device completely useless? Should those be cached and refreshed then periodically?
No it should not be a problem, any command captured by read can be replayed at any time (Even if there is something else in the slot), the ones in my config are 6+ months old. I think that commands in the Xiaomi Home app are also cached in the app and not stored on device.
About the ChecksumError, yes that would be great, atm i'm catching the ChecksumError directly, but would rather catch a DeviceException, but I think that we should make it clear that the token is wrong in that exception.
I created #180 to handle the checksum error (and also for device-delivered errors to allow making a distinction when a device reports an error-case).
I'm not sure I understand what you mean by the commands being able to to be replayed at any time. Do you mean that even when you cannot read them back with ir_read
, invoking them still works?
I'm on mobile so sorry for the formatting.
Yes invoking ir_play with any of the base64 encoded messages will send the correct IR "command" so it would seem like the actual IR "command" is encoded as part of the base64 string and slots are only used for learning as temp. storage.
But I'm pretty sure that the base64 string includes more than just the IR command, as I got slightly different strings after learning the same command twice.
Also another thing: the frequency parameter does not seem to matter, I've tried the default, but I've also tried setting it to 1 just for fun, and the TV turned on in both cases.
Could you execute the commands ir_lean and ir_play again with debug mode enabled and provide the responses?
$ mirobo --ip [ip] --token [token] raw_command miIO.ir_learn '{"key": "1"}'
['ok', 'may be something else?']
I will make sure the response contains only "['ok']".
$ mirobo -d --ip [ip] --token [token] raw_command miIO.ir_learn '{"key": "1"}'
INFO:miio.vacuum_cli:Debug mode active
DEBUG:miio.vacuum_cli:Read stored sequence ids: {'seq': 27, 'manual_seq': 0}
DEBUG:miio.vacuum_cli:Connecting to [ip] with token [token]
Sending cmd miIO.ir_learn with params {'key': '1'}
DEBUG:miio.protocol:Unable to decrypt, returning raw bytes: b''
DEBUG:miio.device:Got a response: Container:
data = Container:
data = (total 0)
value = (total 0)
offset1 = 32
offset2 = 32
length = 0
header = Container:
data = !1\x00 \x00\x00\x00\x00\x03\xef\x8b\xcb\x00\x00\x05\xc8 (total 16)
value = Container:
length = 32
unknown = 0
device_id = 03ef8bcb (total 8)
ts = 1970-01-01 00:24:40
offset1 = 0
offset2 = 16
length = 16
checksum = VC\xcb\x1f\x15&\xa7\xd7t'\xdemo|P\xd2 (total 16)
DEBUG:miio.device:Discovered b'03ef8bcb' with ts: 1970-01-01 00:24:40, token: b'[token]'
DEBUG:miio.device:[ip]:54321 >>: {'id': 28, 'method': 'miIO.ir_learn', 'params': {'key': '1'}}
DEBUG:miio.device:[ip]:54321 (ts: 1970-01-01 00:24:40, id: 28) << {'result': 0, 'id': 28}
0
DEBUG:miio.vacuum_cli:Writing {'seq': 28, 'manual_seq': 0} to /Users/cnrd/Library/Caches/python-miio/python-mirobo.seq
Learn timed out:
$ mirobo -d --ip [ip] --token [token] raw_command miIO.ir_read '{"key": "1"}'
INFO:miio.vacuum_cli:Debug mode active
DEBUG:miio.vacuum_cli:Read stored sequence ids: {'seq': 28, 'manual_seq': 0}
DEBUG:miio.vacuum_cli:Connecting to [ip] with token [token]
Sending cmd miIO.ir_read with params {'key': '1'}
DEBUG:miio.protocol:Unable to decrypt, returning raw bytes: b''
DEBUG:miio.device:Got a response: Container:
data = Container:
data = (total 0)
value = (total 0)
offset1 = 32
offset2 = 32
length = 0
header = Container:
data = !1\x00 \x00\x00\x00\x00\x03\xef\x8b\xcb\x00\x00\x06Y (total 16)
value = Container:
length = 32
unknown = 0
device_id = 03ef8bcb (total 8)
ts = 1970-01-01 00:27:05
offset1 = 0
offset2 = 16
length = 16
checksum = VC\xcb\x1f\x15&\xa7\xd7t'\xdemo|P\xd2 (total 16)
DEBUG:miio.device:Discovered b'03ef8bcb' with ts: 1970-01-01 00:27:05, token: b'[token]'
DEBUG:miio.device:[ip]:54321 >>: {'id': 29, 'method': 'miIO.ir_read', 'params': {'key': '1'}}
DEBUG:miio.device:[ip]:54321 (ts: 1970-01-01 00:27:05, id: 29) << {'error': {'code': -5003, 'message': 'learn timeout'}, 'id': 29}
{'error': {'code': -5003, 'message': 'learn timeout'}, 'id': 29}
DEBUG:miio.vacuum_cli:Writing {'seq': 29, 'manual_seq': 0} to /Users/cnrd/Library/Caches/python-miio/python-mirobo.seq
No learned command in slot:
$ mirobo -d --ip [ip] --token [token] raw_command miIO.ir_read '{"key": "2"}'
INFO:miio.vacuum_cli:Debug mode active
DEBUG:miio.vacuum_cli:Read stored sequence ids: {'seq': 29, 'manual_seq': 0}
DEBUG:miio.vacuum_cli:Connecting to [ip] with token [token]
Sending cmd miIO.ir_read with params {'key': '2'}
DEBUG:miio.protocol:Unable to decrypt, returning raw bytes: b''
DEBUG:miio.device:Got a response: Container:
data = Container:
data = (total 0)
value = (total 0)
offset1 = 32
offset2 = 32
length = 0
header = Container:
data = !1\x00 \x00\x00\x00\x00\x03\xef\x8b\xcb\x00\x00\x06\xed (total 16)
value = Container:
length = 32
unknown = 0
device_id = 03ef8bcb (total 8)
ts = 1970-01-01 00:29:33
offset1 = 0
offset2 = 16
length = 16
checksum = VC\xcb\x1f\x15&\xa7\xd7t'\xdemo|P\xd2 (total 16)
DEBUG:miio.device:Discovered b'03ef8bcb' with ts: 1970-01-01 00:29:33, token: b'[token]'
DEBUG:miio.device:[ip]:54321 >>: {'id': 30, 'method': 'miIO.ir_read', 'params': {'key': '2'}}
DEBUG:miio.device:[ip]:54321 (ts: 1970-01-01 00:29:33, id: 30) << {'error': {'code': -5002, 'message': 'no code for this key'}, 'id': 30}
{'error': {'code': -5002, 'message': 'no code for this key'}, 'id': 30}
DEBUG:miio.vacuum_cli:Writing {'seq': 30, 'manual_seq': 0} to /Users/cnrd/Library/Caches/python-miio/python-mirobo.seq
Learned command in slot:
$ mirobo -d --ip [ip] --token [token] raw_command miIO.ir_read '{"key": "1"}'
INFO:miio.vacuum_cli:Debug mode active
DEBUG:miio.vacuum_cli:Read stored sequence ids: {'seq': 31, 'manual_seq': 0}
DEBUG:miio.vacuum_cli:Connecting to [ip] with token [token]
Sending cmd miIO.ir_read with params {'key': '1'}
DEBUG:miio.protocol:Unable to decrypt, returning raw bytes: b''
DEBUG:miio.device:Got a response: Container:
data = Container:
data = (total 0)
value = (total 0)
offset1 = 32
offset2 = 32
length = 0
header = Container:
data = !1\x00 \x00\x00\x00\x00\x03\xef\x8b\xcb\x00\x00\x07R (total 16)
value = Container:
length = 32
unknown = 0
device_id = 03ef8bcb (total 8)
ts = 1970-01-01 00:31:14
offset1 = 0
offset2 = 16
length = 16
checksum = VC\xcb\x1f\x15&\xa7\xd7t'\xdemo|P\xd2 (total 16)
DEBUG:miio.device:Discovered b'03ef8bcb' with ts: 1970-01-01 00:31:14, token: b'[token]'
DEBUG:miio.device:[ip]:54321 >>: {'id': 32, 'method': 'miIO.ir_read', 'params': {'key': '1'}}
DEBUG:miio.device:[ip]:54321 (ts: 1970-01-01 00:31:14, id: 32) << {'result': {'key': '1', 'code': 'Z6WPAasBAAA5BQAA6gYAAIoNAAAwJAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjABAAAAAAAAAAAAAAABAAAAAAAAAAEAAQAAAAAAAAAAAQABAQEBAAABAAEBAQAAAQQCMAEAAAAAAAAAAAAAAAEAAAAAAAAAAQABAAAAAAAAAAABAAEBAQEAAAEAAQEBAAABBAIwAQAAAAAAAAAAAAAAAQAAAAAAAAABAAEAAAAAAAAAAAEAAQEBAQAAAQABAQEAAAEEAjABAAAAAAAAAAAAAAABAAAAAAAAAAEAAQAAAAAAAAAAAQABAQEBAAABAAEBAQAAAQAA=='}, 'id': 32}
{'key': '1', 'code': 'Z6WPAasBAAA5BQAA6gYAAIoNAAAwJAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjABAAAAAAAAAAAAAAABAAAAAAAAAAEAAQAAAAAAAAAAAQABAQEBAAABAAEBAQAAAQQCMAEAAAAAAAAAAAAAAAEAAAAAAAAAAQABAAAAAAAAAAABAAEBAQEAAAEAAQEBAAABBAIwAQAAAAAAAAAAAAAAAQAAAAAAAAABAAEAAAAAAAAAAAEAAQEBAQAAAQABAQEAAAEEAjABAAAAAAAAAAAAAAABAAAAAAAAAAEAAQAAAAAAAAAAAQABAQEBAAABAAEBAQAAAQAA=='}
DEBUG:miio.vacuum_cli:Writing {'seq': 32, 'manual_seq': 0} to /Users/cnrd/Library/Caches/python-miio/python-mirobo.seq
I've analysed the binary data encoded in the base64 strings provided by @cnrd and I've reverse-engineered the format of the signal. It's really simple and won't be able to properly learn some IR protocols. I won't go into details here as the subject of IR control is really big and ugly.
I was able to extract the signal from the base64 for prosonic power button (it's NEC1, Dev=0, Func=10).
The format stores only a single stream of pulses and gaps. It uses little endian.
$00 - 2 bytes - modulation frequency given as off and on time (one byte each), the unit is [100 nanoseconds], for signals above its: 0xA5=16.5 ms, 0x67=10.3 ms and the frequency can be calculated by freq = 1/(16.5 ms + 10.3 ms) = 1/(26.8 ms) =~ 37.3 kHz
which is consistent with NEC1 signal.
$02 - 2 bytes - number of rising/falling edges + 1
$04 - 16 x 4 bytes - index of 16 4-byte integers representing possible time values in milliseconds, sorted by ascending value - index 0 is at $04, index 1 is at $08 etc.
$44 - start of IR stream - its length is the value from $04 * 4bits, rounded up to a whole byte
Each byte in IR stream represents a pair of a pulse and gap. The least significant 4 bits contain an index position of time of the pulse, followed by a gap which time is contained under index value represented by most significant 4 bits.
Having that information, it should not be hard to write method in the ChuangmiIr class, which would take other signal formats (like the most popular Pronto Hex), convert them on the fly and send them out.
Here's the working Construct for the signal format:
ChuangmiIrSignal = Struct(
'frequency' / Struct(
'off_time' / Byte,
'on_time' / Byte,
),
'edge_count' / Rebuild(Int16ul, len_(this.edge_pairs) * 2 - 1),
'index' / Array(16, Int32ul),
'edge_pairs' / Array((this.edge_count + 1) / 2, BitStruct(
'gap' / BitsInteger(4),
'pulse' / BitsInteger(4),
))
)
@cnrd can you try sending this one?
omJDAD0CAACdBgAAmxEAAFAjAABpmwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjAAAAAAAAAAAQEBAQEBAQEAAQABAAAAAAEAAQABAQEBBA
It should send the prosonic power button, but it's freshly generated from a Pronto Hex code. If this works then I have the prototype code working, which I would just need to cleanup and put into the library.
@syssi where should I put the Construct definitions? Should I create a new module for them or put them directly into the chuangmi_ir? I have two Structs, one for the Chuangmi IR signal format and second one for parsing Pronto.
I would prefer a utility class at the chuangmi_ir.py. @rytilahti has more experience with such decisions. :-)
@yawor This is the response I got from sending that command:
$ mirobo -d --ip [ip] --token [token] raw_command miIO.ir_play '{"freq": 38400, "code": "omJDAD0CAACdBgAAmxEAAFAjAABpmwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjAAAAAAAAAAAQEBAQEBAQEAAQABAAAAAAEAAQABAQEBBA"}'
INFO:miio.vacuum_cli:Debug mode active
DEBUG:miio.vacuum_cli:Read stored sequence ids: {'seq': 32, 'manual_seq': 0}
DEBUG:miio.vacuum_cli:Connecting to [ip] with token [token]
Sending cmd miIO.ir_play with params {'freq': 38400, 'code': 'omJDAD0CAACdBgAAmxEAAFAjAABpmwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjAAAAAAAAAAAQEBAQEBAQEAAQABAAAAAAEAAQABAQEBBA'}
DEBUG:miio.protocol:Unable to decrypt, returning raw bytes: b''
DEBUG:miio.device:Got a response: Container:
data = Container:
data = (total 0)
value = (total 0)
offset1 = 32
offset2 = 32
length = 0
header = Container:
data = !1\x00 \x00\x00\x00\x00\x03\xef\x8b\xcb\x00\x01\xb8\xc4 (total 16)
value = Container:
length = 32
unknown = 0
device_id = 03ef8bcb (total 8)
ts = 1970-01-02 07:20:36
offset1 = 0
offset2 = 16
length = 16
checksum = VC\xcb\x1f\x15&\xa7\xd7t'\xdemo|P\xd2 (total 16)
DEBUG:miio.device:Discovered b'03ef8bcb' with ts: 1970-01-02 07:20:36, token: b'[token]'
DEBUG:miio.device:[ip]:54321 >>: {'id': 33, 'method': 'miIO.ir_play', 'params': {'freq': 38400, 'code': 'omJDAD0CAACdBgAAmxEAAFAjAABpmwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjAAAAAAAAAAAQEBAQEBAQEAAQABAAAAAAEAAQABAQEBBA'}}
DEBUG:miio.device:[ip]:54321 (ts: 1970-01-02 07:20:37, id: 33) << {'error': {'code': -5008, 'message': 'magic error'}, 'id': 33}
{'error': {'code': -5008, 'message': 'magic error'}, 'id': 33}
DEBUG:miio.vacuum_cli:Writing {'seq': 33, 'manual_seq': 0} to /Users/cnrd/Library/Caches/python-miio/python-mirobo.seq
The TV however did not turn on, looks like there was some 'magic error', whatever that is :P
Not sure if you saw this, these are both prosonic on/off commands, but they are captured with a few months between them (Using the same remote): The newest:
Z6VPACwCAACpBgAAyAgAAHYRAADHIgAA0J0AAHB1AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0AAAAAAAAAAAQEBAQEBAQAAAQABAAAAAAEAAQABAQEBBQJGAkYCQA
The older:
Z6VPAAUCAABgAgAAxQYAAOUIAACUEQAAqyIAADSeAABwdQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFEBAQEBAQEBAgICAgICAgEBAgECAQEBAQIBAgECAgICBgNXA1cDUA
As you can see, there is quite a bit of difference between them, but they both turn on/off the TV correctly.
Also here is the command captured four times in a row, both to 'slot: 1' (Captured these just now):
Z6UFANEAAAAjAQAAAwkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQIAE=
Z6VLADcCAACKBgAApQgAAFcRAADpIgAA0J0AAAx1AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0AAAAAAAAAAAQEBAQEBAQAAAQABAAAAAAEAAQABAQEBBQJGAkAA==
I did hold the remote towards the device for a bit longer for the third and fourth capture.
Z6VLACICAABDAgAAhwYAAKQIAABXEQAA6SIAANCdAAAMdQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFAQEBAQEBAQEhISEhISEhAQEhASEBAQEBIQEhASEhISFhNXE1AQ==
Z6VPADgCAACJBgAApggAAMIIAABXEQAA4CIAANCdAAAMdQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFAAAAAAAAAAAQEBAQEBAQAAAQABAAAAAAEAAQABAQEBBgNXAlcCUA
Just to make it completely clear, all six command examples are the same on/off (Red remote button) from the remote that came with the Prosonic TV.
The difference between these two is not an issue. The IR capture is never ideal and you'll almost certainly always get a different result. You can check that by trying to record the same button multiple times. Also because of the way this device records the signal you'll probably get different results because of how long you hold the button during the recording. There is a lot of variables:
The "magic error" is probably because I've misinterpreted first two bytes of the signal format. But it fit so well to the frequency calculation that I thought that it must be it. If these first two bytes are magic bytes, then there's no way to set the carrier frequency and it's locked to ~38 kHz. This means there's no way to control some devices which work at much higher carrier frequencies (like some MCE receivers, which us ~56 kHz).
OK try this one
Z6VDAD0CAACdBgAAmxEAAFAjAABpmwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjAAAAAAAAAAAQEBAQEBAQEAAQABAAAAAAEAAQABAQEBBA
I've set first two bytes to a constant value from your original captured signals. This is again the code for power button.
Actually we set the freq as part of the command: raw_command miIO.ir_play '{"freq": 38400, "code": "om...
but I'm unsure if the device is actually using it, as setting it to 1 works the same.
Not really sure that I can test the frequency theory in any way, as I don't know what frequency any of my remotes use and I have no equipment to test it.
Ah, this explains a lot :). Sorry, I've missed that. That's awesome. Try setting the frequency to 38381. I know it's not a big difference but at least we'll see if if can be set to some arbitrary values.
No errors, but TV does not react to the last command you posted:
$ mirobo -d --ip [ip] --token [token] raw_command miIO.ir_play '{"freq": 38400, "code": "Z6VDAD0CAACdBgAAmxEAAFAjAABpmwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjAAAAAAAAAAAQEBAQEBAQEAAQABAAAAAAEAAQABAQEBBA"}'
INFO:miio.vacuum_cli:Debug mode active
DEBUG:miio.vacuum_cli:Read stored sequence ids: {'seq': 47, 'manual_seq': 0}
DEBUG:miio.vacuum_cli:Connecting to [ip] with token [token]
Sending cmd miIO.ir_play with params {'freq': 38400, 'code': 'Z6VDAD0CAACdBgAAmxEAAFAjAABpmwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjAAAAAAAAAAAQEBAQEBAQEAAQABAAAAAAEAAQABAQEBBA'}
DEBUG:miio.protocol:Unable to decrypt, returning raw bytes: b''
DEBUG:miio.device:Got a response: Container:
data = Container:
data = (total 0)
value = (total 0)
offset1 = 32
offset2 = 32
length = 0
header = Container:
data = !1\x00 \x00\x00\x00\x00\x03\xef\x8b\xcb\x00\x01\xc2; (total 16)
value = Container:
length = 32
unknown = 0
device_id = 03ef8bcb (total 8)
ts = 1970-01-02 08:00:59
offset1 = 0
offset2 = 16
length = 16
checksum = VC\xcb\x1f\x15&\xa7\xd7t'\xdemo|P\xd2 (total 16)
DEBUG:miio.device:Discovered b'03ef8bcb' with ts: 1970-01-02 08:00:59, token: b'[token]'
DEBUG:miio.device:[ip]:54321 >>: {'id': 48, 'method': 'miIO.ir_play', 'params': {'freq': 38400, 'code': 'Z6VDAD0CAACdBgAAmxEAAFAjAABpmwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjAAAAAAAAAAAQEBAQEBAQEAAQABAAAAAAEAAQABAQEBBA'}}
DEBUG:miio.device:[ip]:54321 (ts: 1970-01-02 08:00:59, id: 48) << {'result': 0, 'id': 48}
0
DEBUG:miio.vacuum_cli:Writing {'seq': 48, 'manual_seq': 0} to /Users/cnrd/Library/Caches/python-miio/python-mirobo.seq
Also not sure if you saw that part, I tried setting the freq to 1, the command still worked, so the device may ignore the freq part?
Also tried setting the freq to 38381 (With a known working code) this is the response (TV did turn on):
mirobo -d --ip [ip] --token [token] raw_command miIO.ir_play '{"freq": 38381, "code": "Z6VPADgCAACJBgAApggAAMIIAABXEQAA4CIAANCdAAAMdQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFAAAAAAAAAAAQEBAQEBAQAAAQABAAAAAAEAAQABAQEBBgNXAlcCUA"}'
INFO:miio.vacuum_cli:Debug mode active
DEBUG:miio.vacuum_cli:Read stored sequence ids: {'seq': 48, 'manual_seq': 0}
DEBUG:miio.vacuum_cli:Connecting to [ip] with token [token]
Sending cmd miIO.ir_play with params {'freq': 38381, 'code': 'Z6VPADgCAACJBgAApggAAMIIAABXEQAA4CIAANCdAAAMdQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFAAAAAAAAAAAQEBAQEBAQAAAQABAAAAAAEAAQABAQEBBgNXAlcCUA'}
DEBUG:miio.protocol:Unable to decrypt, returning raw bytes: b''
DEBUG:miio.device:Got a response: Container:
data = Container:
data = (total 0)
value = (total 0)
offset1 = 32
offset2 = 32
length = 0
header = Container:
data = !1\x00 \x00\x00\x00\x00\x03\xef\x8b\xcb\x00\x01\xc3\x01 (total 16)
value = Container:
length = 32
unknown = 0
device_id = 03ef8bcb (total 8)
ts = 1970-01-02 08:04:17
offset1 = 0
offset2 = 16
length = 16
checksum = VC\xcb\x1f\x15&\xa7\xd7t'\xdemo|P\xd2 (total 16)
DEBUG:miio.device:Discovered b'03ef8bcb' with ts: 1970-01-02 08:04:17, token: b'[token]'
DEBUG:miio.device:[ip]:54321 >>: {'id': 49, 'method': 'miIO.ir_play', 'params': {'freq': 38381, 'code': 'Z6VPADgCAACJBgAApggAAMIIAABXEQAA4CIAANCdAAAMdQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFAAAAAAAAAAAQEBAQEBAQAAAQABAAAAAAEAAQABAQEBBgNXAlcCUA'}}
DEBUG:miio.device:[ip]:54321 (ts: 1970-01-02 08:04:17, id: 49) << {'result': 0, 'id': 49}
0
DEBUG:miio.vacuum_cli:Writing {'seq': 49, 'manual_seq': 0} to /Users/cnrd/Library/Caches/python-miio/python-mirobo.seq
If you need more debugging code, just send me a modified version of mirobo and I'll use that instead :-)
Try this
Z6VPAD0CAACdBgAA2ggAAJsRAABQIwAAaZsAAMF3AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0AAAAAAAAAAAQEBAQEBAQEAAQABAAAAAAEAAQABAQEBBQJGAkYCQA
I've added 3 repeat frames at the end like in your original signal. Maybe your TV needs at least 2 or 3 repeat frames for the power button and won't accept the signal otherwise.
Nope :-/ Are you sure that it is the correct Proton code you are using, the specific TV model is: Prosonic PBT-23000
Mea culpa. I've messed up the params for the NEC1 protocol. I'm not using any database. I've decoded your signal to check what it is and then generated new one from a program I'm using (IrScrutinizer, it can parse signal, detect and decode the protocol data, generate signal with any protocol it knows with any data etc). NEC1 has a Device ID and Subdevice ID fields. I've set the Device ID to 0 correctly, but I've missed that your signal has Subdevice ID = 127. I've left a default value which is 255 for dev id 0.
I hope that this one will finally work:
Z6VPAD0CAACdBgAA2ggAAJsRAABQIwAAyZ8AAMF3AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0AAAAAAAAAAAQEBAQEBAQAAAQABAAAAAAEAAQABAQEBBQJGAkYCRg
Yes!
I've created #183 which implements ability to play Pronto codes.
I think the scope of this issue is solved here. Thanks to all!
@cnrd Could you do me a favour and provide a example response of the learn_command call?
I would like to fix this comment: https://github.com/rytilahti/python-miio/blob/master/miio/chuangmi_ir.py#L19
The ouput of these calls would be perfect: