-
-
Notifications
You must be signed in to change notification settings - Fork 32.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add CCL Electronics integration #130281
base: dev
Are you sure you want to change the base?
Add CCL Electronics integration #130281
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to only PR one platform at a time. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
entry.runtime_data = CCLDevice(entry.data["passkey"]) | ||
|
||
CCLServer.add_copy(entry.runtime_data) | ||
await CCLServer.run() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you are launching your own webserver here which is not something we want. There is a built in webhook
component that can be used to allow push style HTTP callbacks, take a look at tedee
for how those are registered. Also, is there any way you can push the instance details to CCL, instead of the user having to go to the app to configure that manually?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the advice. It is now changed to listen for requests using webhook
api.
Here is the test command I input to the zsh terminal in dev container (about half of them are binary sensors which are not included in this PR):
curl localhost:8123/api/webhook/c2507495 -X POST -H 'Content-Type: application/json' -d '{"serial_no": "1061616322","mac_address": "48:31:B7:06:D5:59","model":"HA100","fw_ver":"v1.00","datetime":"2024-12-26+02:47:46","abar":1014.1,"rbar":1012.9,"t1dew":16.1,"t1feels":22.9,"t1chill":22.9,"inhum":63,"intem":23.0,"t1solrad":0,"t1hum":66,"t1tem":22.9,"t1rainra":0,"t1raindy":0,"t1rainhr":0,"t1rainmth":0,"t1rainwy":0,"t1rainyr":0,"t1uvi":0,"t1wdir":276,"t1wgust":0,"t1ws":0,"t1ws10mav":0,"inbat":1,"t1bat":0,"t234c1cn":0,"t234c2cn":0,"t234c3cn":0,"t234c4cn":0,"t234c5cn":0,"t234c6cn":0,"t234c7cn":0,"t11cn":0,"t10cn":0,"t9cn":0,"t6c1cn":0,"t6c2cn":0,"t6c3cn":0,"t6c4cn":0,"t6c5cn":0,"t6c6cn":0,"t6c7cn":0,"t5lscn":0,"t1cn":1,"t8cn":0,"api_ver":"v1.00"}'
Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍 |
PLATFORMS: list[Platform] = [Platform.SENSOR] | ||
|
||
|
||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please register a custom type for the entry
|
||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: | ||
"""Set up a config entry for a single CCL device.""" | ||
entry.runtime_data = CCLDevice(entry.data[CONF_WEBHOOK_ID]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
preference: put stuff only in the runtime data once the rest is done
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: | ||
"""Set up a config entry for a single CCL device.""" | ||
entry.runtime_data = CCLDevice(entry.data[CONF_WEBHOOK_ID]) | ||
CCLServer.register(entry.runtime_data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can this fail?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it will never fail if CONF_WEBHOOK_ID exists
VERSION = 1 | ||
_webhook_id: str | ||
|
||
async def async_step_user( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how does this actually work? Like how do you know which weather station to register with, without the user being able to input anything?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It generates a random path. We have a mobile app detecting nearby devices, data will be pushed once you input that path in the configuration of a certain device.
@property | ||
def device_name(self) -> str: | ||
"""Return the device name.""" | ||
if self.internal.compartment is not None: | ||
return self.device.name + " " + self.internal.compartment | ||
return self.device.name | ||
|
||
@property | ||
def device_id(self) -> str: | ||
"""Return the 6-digits device id.""" | ||
if self.internal.compartment is not None: | ||
return ( | ||
(self.device_name + "_" + self.internal.compartment) | ||
.replace(" ", "") | ||
.replace("-", "_") | ||
.lower() | ||
) | ||
return self.device_name.replace(" ", "").replace("-", "_").lower() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like those properties if they are only used in init (tbh not sure that even works?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed them as properties
async_add_entities: AddEntitiesCallback, | ||
) -> None: | ||
"""Add sensors for passed config entry in HA.""" | ||
device: CCLDevice = entry.runtime_data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
device: CCLDevice = entry.runtime_data | |
device = entry.runtime_data |
will be inferred once you have the custom entry type
device.register_new_sensor_cb(_new_sensor) | ||
entry.async_on_unload(lambda: device.remove_new_sensor_cb(_new_sensor)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's happening here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just appending the add sensor callback to a list in the device, to be executed when new sensor data is received. I'm also removing that from the list on entry unload.
Co-authored-by: Josef Zweck <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New integrations are required to have a quality_scale.yaml
and reach at least bronze. Please add that and make sure you implement the required rules
if CONF_WEBHOOK_ID is None: | ||
return False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would a constant be None?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I worried it might cause errors in the CCLServer.register, but it doesn't. These lines have been deleted.
CCLServer.register(new_device) | ||
|
||
async def register_webhook() -> None: | ||
def handle_webhook( | ||
hass: HomeAssistant, webhook_id: str, request: web.Request | ||
) -> Any: | ||
"""Handle incoming webhook from CCL devices.""" | ||
return CCLServer.handler(request) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the CCLServer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't run a server by itself but rather provides functions to be imported. The CCLServer.register adds new_device to a dictionary of devices with the key CONF_WEBHOOK_ID. Whenever a webhook catches an HTML request pushed from a device, the CCLServer.handler will process data and update the internal values of the device sensors through the dictionary.
Co-authored-by: Michael Arthur <[email protected]>
Proposed change
Adds the CCL Electronics integration, allowing local weather stations with expandable modules to push sensor data.
Link to library: https://github.com/CCL-Electronics-Ltd/aioccl
Type of change
Additional information
Checklist
ruff format homeassistant tests
)If user exposed functionality or configuration variables are added/changed:
If the code communicates with devices, web services, or third-party tools:
Updated and included derived files by running:
python3 -m script.hassfest
.requirements_all.txt
.Updated by running
python3 -m script.gen_requirements_all
.To help with the load of incoming pull requests: