scottyphillips / pychonet Goto Github PK
View Code? Open in Web Editor NEWA simple to use library for interfacing with the ECHONETlite protocol
License: GNU General Public License v3.0
A simple to use library for interfacing with the ECHONETlite protocol
License: GNU General Public License v3.0
After carefully reading the ECHONET Lite specifications, it states that when making consecutive requests to a device, wait for a response before making the next request. It seems that the controller design should conform to that.
rel. #56
Couple of units (Panasonics) look like they make use of this sensor, just need to update to HomeAirConditioner to fix up the bytecode 0xBA with the overflow, underflow and unavailable values.
Hi,
I tested the code against my AC and it listed all the property maps correctly:
192.168.1.40 - ECHONET Node Discovery Successful!
192.168.1.40 - ECHONET Instance 0x1-0x30-0x1 map attributes discovered!
192.168.1.40 - ECHONET Instance 0x1-0x30-0x1 identification number discovered!
[{'eojcc': '0x30',
'eojci': '0x1',
'eojgc': '0x1',
'getmap': ['0x80',
'0xa0',
'0xb0',
'0x81',
'0x82',
'0x83',
'0x93',
'0xa3',
'0xb3',
'0x84',
'0xb4',
'0x85',
'0x88',
'0x89',
'0x8a',
'0xba',
'0xbb',
'0x9d',
'0x9e',
'0xbe',
'0x8f',
'0x9f'],
'host': '192.168.1.40',
'manufacturer': 'DAIKIN INDUSTRIES',
'setmap': ['0x80',
'0x81',
'0x8f',
'0x93',
'0xa0',
'0xa3',
'0xb0',
'0xb3',
'0xb4'],
'uid': '000008dcf5055cf84a00000000000000'}]
Running the same code against my light device with multiple instance, all the instances are correctly list, but the property maps are not shown:
192.168.1.50 - ECHONET Node Discovery Successful!
192.168.1.50 - ECHONET Instance 0x2-0x90-0x1 map attributes discovered!
192.168.1.50 - ECHONET Instance 0x2-0x90-0x1 identification number discovered!
192.168.1.50 - ECHONET Instance 0x2-0x90-0x2 map attributes discovered!
192.168.1.50 - ECHONET Instance 0x2-0x90-0x2 identification number discovered!
192.168.1.50 - ECHONET Instance 0x2-0x90-0x3 map attributes discovered!
192.168.1.50 - ECHONET Instance 0x2-0x90-0x3 identification number discovered!
192.168.1.50 - ECHONET Instance 0x2-0x90-0x4 map attributes discovered!
192.168.1.50 - ECHONET Instance 0x2-0x90-0x4 identification number discovered!
192.168.1.50 - ECHONET Instance 0x2-0x90-0x5 map attributes discovered!
192.168.1.50 - ECHONET Instance 0x2-0x90-0x5 identification number discovered!
192.168.1.50 - ECHONET Instance 0x2-0x90-0x6 map attributes discovered!
192.168.1.50 - ECHONET Instance 0x2-0x90-0x6 identification number discovered!
192.168.1.50 - ECHONET Instance 0x2-0x90-0x7 map attributes discovered!
192.168.1.50 - ECHONET Instance 0x2-0x90-0x7 identification number discovered!
192.168.1.50 - ECHONET Instance 0x2-0x90-0x8 map attributes discovered!
192.168.1.50 - ECHONET Instance 0x2-0x90-0x8 identification number discovered!
I would expect them to also be shown, same as for my AC. I am wrong, or this there something wrong?
Hello Again!
I have found a new bug I think though I can only vaguely describe the symptoms.
I’ve recently noticed that if we’re away from home for more than a day the HA front end crashes…this never seems to happen when we are at home. Needless to say this is a very hard thing to work on as I have to leave home for a long time to see if I can get the error to occur…
Last night it crashed again and I’ve pulled the logs…they look entirely normal until just before the crash and then there are references to exceptions, loops, and bunch of other stuff...but much of it is centered on pychonet. I don't know what causes the crash except it happens when we're not at home....it might be possible for it to happen when we are home too, but I can't say I've ever noticed it.
Below is what I see in the log, but the important part to note is that for whatever reason when the echonet module gets an error the backend library it uses issues a quit() command and that makes the whole Home Assistant exit.
2021-11-18 19:16:13 ERROR (stream_worker) [root] Uncaught thread exception
Traceback (most recent call last):
File “/usr/local/lib/python3.9/threading.py”, line 973, in _bootstrap_inner
self.run()
File “/usr/local/lib/python3.9/threading.py”, line 910, in run
self._target(*self._args, **self._kwargs)
File “/usr/src/homeassistant/homeassistant/components/stream/init.py”, line 284, in _run_worker
stream_worker(
File “/usr/src/homeassistant/homeassistant/components/stream/worker.py”, line 489, in stream_worker
segment_buffer.mux_packet(packet)
File “/usr/src/homeassistant/homeassistant/components/stream/worker.py”, line 175, in mux_packet
self.flush(packet, last_part=True)
File “/usr/src/homeassistant/homeassistant/components/stream/worker.py”, line 247, in flush
self._hass.loop.call_soon_threadsafe(
File “/usr/local/lib/python3.9/asyncio/base_events.py”, line 791, in call_soon_threadsafe
self._check_closed()
File “/usr/local/lib/python3.9/asyncio/base_events.py”, line 510, in _check_closed
raise RuntimeError(‘Event loop is closed’)
RuntimeError: Event loop is closed
2021-11-18 19:16:13 ERROR (stream_worker) [root] Uncaught thread exception
Traceback (most recent call last):
File “/usr/local/lib/python3.9/threading.py”, line 973, in _bootstrap_inner
self.run()
File “/usr/local/lib/python3.9/threading.py”, line 910, in run
self._target(*self._args, **self._kwargs)
File “/usr/src/homeassistant/homeassistant/components/stream/init.py”, line 284, in _run_worker
stream_worker(
File “/usr/src/homeassistant/homeassistant/components/stream/worker.py”, line 489, in stream_worker
segment_buffer.mux_packet(packet)
File “/usr/src/homeassistant/homeassistant/components/stream/worker.py”, line 175, in mux_packet
self.flush(packet, last_part=True)
File “/usr/src/homeassistant/homeassistant/components/stream/worker.py”, line 247, in flush
self._hass.loop.call_soon_threadsafe(
File “/usr/local/lib/python3.9/asyncio/base_events.py”, line 791, in call_soon_threadsafe
self._check_closed()
File “/usr/local/lib/python3.9/asyncio/base_events.py”, line 510, in _check_closed
raise RuntimeError(‘Event loop is closed’)
RuntimeError: Event loop is closed
2021-11-18 19:16:14 ERROR (Thread-3) [paho.mqtt.client] Caught exception in on_message: Event loop is closed
2021-11-18 19:16:14 ERROR (Thread-3) [root] Uncaught thread exception
Traceback (most recent call last):
File “/usr/local/lib/python3.9/threading.py”, line 973, in _bootstrap_inner
self.run()
File “/usr/local/lib/python3.9/threading.py”, line 910, in run
self._target(*self._args, **self._kwargs)
File “/usr/local/lib/python3.9/site-packages/paho/mqtt/client.py”, line 3591, in _thread_main
self.loop_forever(retry_first_connection=True)
File “/usr/local/lib/python3.9/site-packages/paho/mqtt/client.py”, line 1756, in loop_forever
rc = self._loop(timeout)
File “/usr/local/lib/python3.9/site-packages/paho/mqtt/client.py”, line 1164, in _loop
rc = self.loop_read()
File “/usr/local/lib/python3.9/site-packages/paho/mqtt/client.py”, line 1556, in loop_read
rc = self._packet_read()
File “/usr/local/lib/python3.9/site-packages/paho/mqtt/client.py”, line 2439, in _packet_read
rc = self._packet_handle()
File “/usr/local/lib/python3.9/site-packages/paho/mqtt/client.py”, line 3033, in _packet_handle
return self._handle_publish()
File “/usr/local/lib/python3.9/site-packages/paho/mqtt/client.py”, line 3327, in _handle_publish
self._handle_on_message(message)
File “/usr/local/lib/python3.9/site-packages/paho/mqtt/client.py”, line 3570, in _handle_on_message
on_message(self, self._userdata, message)
File “/usr/src/homeassistant/homeassistant/components/mqtt/init.py”, line 850, in _mqtt_on_message
self.hass.add_job(self._mqtt_handle_message, msg)
File “/usr/src/homeassistant/homeassistant/core.py”, line 333, in add_job
self.loop.call_soon_threadsafe(self.async_add_job, target, *args)
File “/usr/local/lib/python3.9/asyncio/base_events.py”, line 791, in call_soon_threadsafe
self._check_closed()
File “/usr/local/lib/python3.9/asyncio/base_events.py”, line 510, in _check_closed
raise RuntimeError(‘Event loop is closed’)
RuntimeError: Event loop is closed
2021-11-18 19:16:15 ERROR (stream_worker) [root] Uncaught thread exception
Traceback (most recent call last):
File “/usr/local/lib/python3.9/threading.py”, line 973, in _bootstrap_inner
self.run()
File “/usr/local/lib/python3.9/threading.py”, line 910, in run
self._target(*self._args, **self._kwargs)
File “/usr/src/homeassistant/homeassistant/components/stream/init.py”, line 284, in _run_worker
stream_worker(
File “/usr/src/homeassistant/homeassistant/components/stream/worker.py”, line 489, in stream_worker
segment_buffer.mux_packet(packet)
File “/usr/src/homeassistant/homeassistant/components/stream/worker.py”, line 175, in mux_packet
self.flush(packet, last_part=True)
File “/usr/src/homeassistant/homeassistant/components/stream/worker.py”, line 247, in flush
self._hass.loop.call_soon_threadsafe(
File “/usr/local/lib/python3.9/asyncio/base_events.py”, line 791, in call_soon_threadsafe
self._check_closed()
File “/usr/local/lib/python3.9/asyncio/base_events.py”, line 510, in _check_closed
raise RuntimeError(‘Event loop is closed’)
RuntimeError: Event loop is closed
2021-11-18 19:16:17 ERROR (MainThread) [homeassistant] Error doing job: Task was destroyed but it is pending!
2021-11-18 19:16:17 ERROR (MainThread) [homeassistant] Error doing job: Task was destroyed but it is pending!
2021-11-18 19:16:17 ERROR (MainThread) [homeassistant] Error doing job: Task was destroyed but it is pending!
2021-11-18 19:16:17 ERROR (MainThread) [homeassistant] Error doing job: Task was destroyed but it is pending!
2021-11-18 19:16:17 ERROR (MainThread) [homeassistant] Error doing job: Task was destroyed but it is pending!
2021-11-18 19:16:17 ERROR (MainThread) [homeassistant] Error doing job: Task was destroyed but it is pending!
2021-11-18 19:16:17 ERROR (MainThread) [homeassistant] Error doing job: Task was destroyed but it is pending!
2021-11-18 19:16:17 ERROR (MainThread) [homeassistant] Error doing job: Task was destroyed but it is pending!
2021-11-18 19:16:17 ERROR (MainThread) [homeassistant] Error doing job: Task was destroyed but it is pending!
2021-11-18 19:16:17 ERROR (MainThread) [homeassistant] Error doing job: Task was destroyed but it is pending!
2021-11-18 19:16:17 ERROR (MainThread) [homeassistant] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
File “/usr/local/lib/python3.9/site-packages/pychonet/lib/functions.py”, line 60, in buildEchonetMsg
raise ValueError(‘Transaction ID is larger then 2 bytes.’)
ValueError: Transaction ID is larger then 2 bytes.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File “/usr/src/homeassistant/homeassistant/runner.py”, line 121, in run
return loop.run_until_complete(setup_and_run_hass(runtime_config))
File “/usr/local/lib/python3.9/asyncio/base_events.py”, line 629, in run_until_complete
self.run_forever()
File “/usr/local/lib/python3.9/asyncio/base_events.py”, line 596, in run_forever
self._run_once()
File “/usr/local/lib/python3.9/asyncio/base_events.py”, line 1890, in _run_once
handle._run()
File “/usr/local/lib/python3.9/asyncio/events.py”, line 80, in _run
self._context.run(self._callback, *self._args)
File “/config/custom_components/echonetlite/sensor.py”, line 159, in async_update
await self._instance.async_update()
File “/config/custom_components/echonetlite/init.py”, line 247, in async_update
batch_data = await self._instance.update(flags)
File “/usr/local/lib/python3.9/site-packages/pychonet/EchonetInstance.py”, line 110, in update
response = await self._api.echonetMessage(self._host, self._eojgc, self._eojcc, self._eojci, GET, opc)
File “/usr/local/lib/python3.9/site-packages/pychonet/echonetapiclient.py”, line 59, in echonetMessage
payload = buildEchonetMsg({
File “/usr/local/lib/python3.9/site-packages/pychonet/lib/functions.py”, line 105, in buildEchonetMsg
quit()
File “/usr/local/lib/python3.9/_sitebuiltins.py”, line 26, in call
raise SystemExit(code)
SystemExit: None
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File “/usr/local/lib/python3.9/site-packages/pychonet/lib/functions.py”, line 60, in buildEchonetMsg
raise ValueError(‘Transaction ID is larger then 2 bytes.’)
ValueError: Transaction ID is larger then 2 bytes.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File “/usr/src/homeassistant/homeassistant/main.py”, line 318, in main
exit_code = runner.run(runtime_conf)
File “/usr/src/homeassistant/homeassistant/runner.py”, line 124, in run
_cancel_all_tasks_with_timeout(loop, TASK_CANCELATION_TIMEOUT)
File “/usr/src/homeassistant/homeassistant/runner.py”, line 145, in _cancel_all_tasks_with_timeout
loop.run_until_complete(asyncio.wait(to_cancel, timeout=timeout))
File “/usr/local/lib/python3.9/asyncio/base_events.py”, line 629, in run_until_complete
self.run_forever()
File “/usr/local/lib/python3.9/asyncio/base_events.py”, line 596, in run_forever
self._run_once()
File “/usr/local/lib/python3.9/asyncio/base_events.py”, line 1890, in _run_once
handle._run()
File “/usr/local/lib/python3.9/asyncio/events.py”, line 80, in _run
self._context.run(self._callback, *self._args)
File “/config/custom_components/echonetlite/sensor.py”, line 159, in async_update
await self._instance.async_update()
File “/config/custom_components/echonetlite/init.py”, line 247, in async_update
batch_data = await self._instance.update(flags)
File “/usr/local/lib/python3.9/site-packages/pychonet/EchonetInstance.py”, line 110, in update
response = await self._api.echonetMessage(self._host, self._eojgc, self._eojcc, self._eojci, GET, opc)
File “/usr/local/lib/python3.9/site-packages/pychonet/echonetapiclient.py”, line 59, in echonetMessage
payload = buildEchonetMsg({
File “/usr/local/lib/python3.9/site-packages/pychonet/lib/functions.py”, line 105, in buildEchonetMsg
quit()
File “/usr/local/lib/python3.9/_sitebuiltins.py”, line 26, in call
raise SystemExit(code)
SystemExit: None
After that there is nothing until the system restarts…which I can do via SSH to the console and issuing a ha core restart command...but the system really is down - for example in this case there is a seventeen hour gap in my power consumption data so it's really dead....
Thanks!
CP.
During coding the light component of HA, I found that pychonet used different interfaces. With this I mean, sometimes you have the original HEX e.g. 0x12, sometimes without the 0x, but sending messages uses integer and in case of the light the hex/int are even replaced with the string:
values = {
0x40: 'other',
0x41: 'incandescent_lamp_color',
0x42: 'white',
0x43: 'daylight_white',
0x43: 'daylight_color',
}
This made coding the HA component quite hacky. I need to send messages in integer, but the state array is populated with strings, but when I request some data it can also be hex. I think it is better to find a common interface.
The most logic for me would be, keep the lowest interfaces for getting data and sending messages in hex (just as echonetlite definition). than make some higher level interfaces using integer or even higher ones using strings. Then we can leave it to the developer of the down stream code to chose the interface they like. Now they need to dance around the API and need to know all those hex/interger things of echnonet anyway.
The badge in the README shows the latest release as 1.0.8
However, the current release on PyPi is 2.0.12 (taken from setup.py
since it's pointing to the async branch)
On GitHub, the latest git tag is 2.0.11, but I guess GitHub only considers the master branch so the latest version is shown as 1.0.8.
Is it just in a transition period where the async branch will soon be merged into master?
ECHONET Lite can be notified of device changes by listening to UDP port 3610 at the multicast address 224.0.23.0.
For example, turning 0x90
to on (0x41
) / off (0x42
) on a device with 0x02
- 0x72
, it will get following data.
on: 10 81 00 28 02 72 01 0e f0 01 73 01 90 01 41
off: 10 81 00 29 02 72 01 0e f0 01 73 01 90 01 42
I think that you can use this to update the device changes immediately.
But I'm not sure how to implement as server functionality in Python.
Do we have a chance to implement this?
The ECHONETLite Machine readable Appendix (MRA) provides a JSON formatted representation of ECHONETLite. In the second major redesign of this library, we could look up the MRA in order to parse data rather then trying to hand code objects all the time. Big job to redesign. But could be very worthwhile and save continued effort. Would also provide a built in JA translation for its natural domestic market. May also work better with Home Assistant.
https://echonet.jp/spec-en/#standard-08
MRA Structure
The MRA provides:
Definitions.json
-> describes the format of echonetlite payloads.
Also provides devices
, node-profile
and superclass
json files. Payloads also can be described within objects, or in the definitions file.
Other considerations:
One thing I am unsure of is the 'mcrules' files. (From release notes: The files in the folder MCRules are used to generate Device Descriptions for the ECHONET Lite Web API). Think these can be ignored.
Where I think version 3.0 will be different:
There will be no more Python objects like 'HomeAirConditioner' etc and no more class-specific getters/setters. This is less of an issue to Home Assistant as it appears. Pychonet 2.0 currently uses class specific getter/setters merely as wrappers to setMessage
and could be cleaned up out of the home-assistant custom component in preparation.
Design Changes:
Example flow:
0x01:0x30 Home Air Conditioner.
EPC: 0xA0
if type['data'] == 'oneOf':
value = OneOf(self, edt)
def OneOf(EchonetLite, edt):
array = EchonetLite.type['data']['oneOf']
for each array value:
test EDT against value
if if value['type'] == state:
test EDT against enum:
if enum matches EDT value, return data (eg 0x41 return 'auto')
if value['type'] == level
test EDT against value range
if within range return value.
return['unsupported value']
@scottyphillips I am considering releasing v2.3.3.
But I'm new to registering on pypi, so check out the working instructions.
I plan to upload using the following command.
python setup.py sdist
python setup.py bdist_wheel
python -m twine upload --repository pypi dist/*
I uploaded it to test.pypi.org with the version number 2.3.2. (By mistake it also uploaded 2.3.2.1 which I tried locally...)
After that, is it OK to just rewrite the version number and upload it to pypi.org?
I'm running HA as a rootless container and it isn't easy to include additional packages.
Is there an alternative installation method so I can use echonetlite with HA
At present my work around is
podman exec -it hass pip3 install pychonet
Ive been using setup.py forever but it might be better to follow the more up to date guide for publishing packages.
https://packaging.python.org/en/latest/tutorials/packaging-projects/
This would require a new metadata layout.
I'm working on including a property value in the EPC_FUNCTIONS constant.
It is possible to simplify the ENL_OP_CODES definition by referencing EPC_FUNCTIONS on the echonetlite integration side.
for example. . .
class ElectricBlind(EchonetInstance):
EPC_FUNCTIONS = {
0xE0: [
_int,
{
0x41: "open",
0x42: "close",
0x43: "stop",
},
],
}
0xE0: {
CONF_ICON: "mdi:roller-shade",
CONF_ICONS: {
OPEN: "mdi:roller-shade",
CLOSE: "mdi:roller-shade-closed",
STOP: "mdi:roller-shade",
},
# TYPE_SELECT: {OPEN: 0x41, CLOSE: 0x42, STOP: 0x43},
TYPE_SELECT: True,
}
if type(options[TYPE_SELECT]) == dict:
self._options = options[TYPE_SELECT]
else:
# Read from _instance.EPC FUNCTIONS definition
# Swap key, value of _instance.EPC_FUNCTIONS[opc][1]
self._options = {
v: k for k, v in connector._instance.EPC_FUNCTIONS[code][1].items()
}
During my debugging I found that pychonet crashed hard, when providing wrong data. Here the example that might cause the crash of home assistant.
Traceback (most recent call last):
File "troubleshoot.py", line 128, in
asyncio.run(main())
File "/usr/lib64/python3.8/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/usr/lib64/python3.8/asyncio/base_events.py", line 616, in run_until_complete
return future.result()
File "troubleshoot.py", line 115, in main
device9 = Factory("192.168.1.50", host, 2,163, 1)
File "/home/martin/workspace/pychonet/pychonet/init.py", line 14, in Factory
instance = EOJX_CLASS[eojgc][eojcc]
KeyError: 163
Better to check all parameters before processing them, to avoid such crashes.
After updating pychonet to 2.6.3 the echonetlite integration fails to load for me with the following exception
Traceback (most recent call last):
File "/var/lib/homeassistant/lib/python3.11/site-packages/homeassistant/setup.py", line 251, in _async_setup_component
component = integration.get_component()
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/lib/homeassistant/lib/python3.11/site-packages/homeassistant/loader.py", line 827, in get_component
ComponentProtocol, importlib.import_module(self.pkg_path)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
File "<frozen importlib._bootstrap>", line 1147, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 940, in exec_module
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "/home/homeassistant/.homeassistant/custom_components/echonetlite/__init__.py", line 5, in <module>
import pychonet as echonet
File "/var/lib/homeassistant/lib/python3.11/site-packages/pychonet/__init__.py", line 6, in <module>
from .ElectricBlind import ElectricBlind
File "/var/lib/homeassistant/lib/python3.11/site-packages/pychonet/ElectricBlind.py", line 1, in <module>
from deprecated import deprecated
ModuleNotFoundError: No module named 'deprecated'
It looks like the import in question was added by 9d6b794
Any idea how to fix this? Thanks in advance!
Line 29 in fcd24e9
As the title says. Would it be possible for you to make me contributor. So I can fix such things directly myself, as I spot them.
@scottyphillips I am not familiar with network technology, so please let me ask you a question.
It's currently running on a single socket with UDP send and receive. Wouldn't this be a problem in terms of stability?
Also, looking at the communication of other EchoNet Lite devices, the transmission port seems to be random.
Does it make sense to have separate send and receive sockets and random send ports in this library?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.