Hubspace-Homeassistant icon indicating copy to clipboard operation
Hubspace-Homeassistant copied to clipboard

Implement Proper Device Types

Open shawngmc opened this issue 2 years ago • 18 comments

Currently, all devices are a variant of a Light Entity.

As a proof-of-concept, I've split out Fan entities into the proper fan type on a fork at https://github.com/shawngmc/Hubspace-Homeassistant; however, #18 would change things drastically/make the implementation much easier.

I don't have any other entity types to test - Lock, Outlet, etc.

shawngmc avatar Jan 05 '23 00:01 shawngmc

This is a great start. Looking at other integrations, if you add to your init.py setup() function:

hass.data[DOMAIN]["client"] = HubSpace(username,password) # need to get user/password first, and try/catch, etc

then you can call hass.data[DOMAIN]["client"] instead of making a new hubsapce in the light/lock entities. Not sure this will work, but please try if you have time.

#18 would help, but once things are centralized moving to a config flow may be easier.

jdeath avatar Jan 05 '23 03:01 jdeath

So doing a little digging, I'm not sure I'm comfortable with putting anything sensitive in hass.data.

I've opened a ticket on it, but in short:

  • hass.data can handle stateful objects ok (such as a websocket connection)
  • hass.data is visible to all integrations in the system... while I need to trust all integrations in the system, this seems like too much access

I need to dig - without using hass.data, I'm not sure how sensitive data should be shared between setup_components and the individual entities.

shawngmc avatar Jan 05 '23 21:01 shawngmc

I'm wondering if the second option in the component docs may be the right way to handle it.

If the component fetches data that causes its related platform entities to update, you can notify them using the dispatcher code in homeassistant.helpers.dispatcher.

So, the correct setup might be:

  • The component (init.py) reads the config and connects to the Hubspace API.
  • The component dispatches info on what devices exist?
  • The individual entities look at this published data and make the entities?
  • The entities call back to the component to make a change... somehow?

The dispatcher docs are kinda spartan though.

On an unrelated note, what are your thoughts on switching to a pre-existing python package on PyPi (creatively named hubspace) (source here)?

This would fit 4.1 of the HASS Component guidelines, and drastically reduce how much this project needs to maintain. It would also be a good step towards making this an official integration.

shawngmc avatar Jan 05 '23 21:01 shawngmc

I'm looking at the polling docs and the WeMo component source as an example.

In the docs, it mentions that the simple case is one device = one entity. However, WeMo - like Hubspace - has combined devices as well. When this occurs, the docs recommend using a DataUpdateCoordinator to take the read-in data and send it to the right entity.

This kinda makes sense - right now, a fan/light combo has two entities. Each of these entities is separately reaching out to hubspace on SCAN_INTERVAL via the Entity objects' update function. That means that a fan/light combo pulls the same data twice, a three outlet smart plug three times, etc.

WeMo uses a Dispatcher and a DataUpdateCoordinator. It has a WemoEntity that all devices inherit, and that provides a lot of the functionality.

On the other hand, DeviceCoordinator looks complicated. It seems like the right way for a component to publish data to the platform entities, but there's a lift.

The reverse direction is actually pretty easy thanks to the vendor entity (WemoEntity, in the example). It has a reference to a wemo API object, WeMoDevice, that actually makes changes. This API object is passed in when the WeMoDevice is created.

We could either:

  • Use the hubspace project on PyPi, which has a HubSpaceDevice that functionally works like WeMoDevice does in the WeMo python API
  • Write our own around the current hubspace API code; this shouldn't be too hard, but does end up duplicating work we could inherit

In either case, this vendor device class then exposes functions to contact HubSpace.

shawngmc avatar Jan 05 '23 22:01 shawngmc

Yeah, it is all so complicated, that is why I never bothered. Thanks for the research. Copying the Wemo sounds like a good place to start.

I also tried to avoid making a PyPi package. That makes any updates a pain, because need to update the package too if need any changes. Also making a PyPi package required a bunch of time and effort I didn't feel like doing. They require it for a real integration, for some reason. You can get 100% the same capability by just making a folder, putting the hubspace.py in it and adding an init.py file in the folder.

Looks like someone took my code and made that PyPi package. I see they totally copied everything. Man, not even a shoutout! Best to make your own pypi, because there will probably need to be changes and don't want to rely on someone else.

jdeath avatar Jan 06 '23 00:01 jdeath

Looks like someone took my code and made that PyPi package. I see they totally copied everything. Man, not even a shoutout!

Hmm... yeah, based on the debugging output, they definitely copied yours.

Technically, since you didn't list a license in the repo (typically done via a LICENSE file in the root like they did), they don't have a license to use it. They incorrectly assumed that it was public domain (this is not uncommon), when it actually is under default copyright law, "All Rights Reserved".

You could reach out to them and ask them to take it down (it's technically within your rights). You could also add an MIT license to yours and then just reach out and ask for attribution.

That said, I only found it by searching hubspace on PyPi, and it doesn't look to be very popular. I used PyPi's Google BigQuery dataset to check downloads - 151 times in the last 30 days, ~3000 in the last year.

Best to make your own pypi, because there will probably need to be changes and don't want to rely on someone else.

Counterargument: Ideally, we rely on someone else. :)

  • Someone with more websocket experience could contribute that.
  • If something breaks with the library, there will be more eyes on it and more people that could contribute a fix.
  • It allows you to focus on making the bridge between the hubspace library and HA APIs.
  • The library is MIT licensed, so it's open source. If it becomes a problem (they don't update, they rearchitect in a way that's a problem), you can fork it and make your own PyPi library then.

I've set up a PyPi project before, so I know how to set it up. That said, their code is much more pythonic and succinct - not saying yours is bad, but they've made classes to describe the user account and device. Those classes have been present from their first checkin that has code.

If anything, we might just want to fork theirs. :)

Even if we adapt yours directly, ideally other people interested in hubspace contribute to your/our PyPi library.

shawngmc avatar Jan 06 '23 01:01 shawngmc

I don't care about stolen code. I reverse engineered it, so technically its afero's code. It was just funny that someone did that.

Agree, might be better if someone else maintained it, but that code is 7 months old, made in one day, and not touched since.

My code stinks. I only do it good enough to work, and learned python from google. I probably should have stopped once I got my light working and let someone who knows how to code handle everyone else's devices! That might be you!

jdeath avatar Jan 06 '23 01:01 jdeath

Sorry for the delay - time to work on this has been more limited than expected.

I've been working on a library based on the design from arraylabs' pymyq library, which is used in the official MyQ integration.

I have Light and Fan devices implemented; I have some code cleanup to do before I put out a first release, but I need to figure out how I can work on some other device types.

shawngmc avatar Jan 25 '23 16:01 shawngmc

OK, I have a public repo at https://github.com/shawngmc/hubspace-ng. I haven't submitted it to PyPi yet, as I'd like to get more device types implemented. I'm going to look through the sample data you've accumulated, but can you help me find users to help test some device types?

shawngmc avatar Jan 27 '23 03:01 shawngmc

Awesome. I would say just post on the home assistant thread, that is where most questions get asked. Maybe list models you want data from. Most of the models numbers are hard coded. I posted a lock in the sample data too.

jdeath avatar Jan 27 '23 03:01 jdeath

If it's helpful at all, I have a few locks (Defiant) if I can test anything or gather any info.

jasonhurlbert avatar Feb 06 '23 03:02 jasonhurlbert

@jdeath : Awesome. I would say just post on the home assistant thread, that is where most questions get asked. Maybe list models you want data from. Most of the models numbers are hard coded. I posted a lock in the sample data too.

Post added. I'm trying to not track models by ID - so far, I haven't seen anything between models that means I need to. And I'll take a look at the sample lock data you added.

@jasonhurlbert : If it's helpful at all, I have a few locks (Defiant) if I can test anything or gather any info.

That would be a huge help, if you have basic Git/Python experience, please:

  1. Pull the source code for the main branch of the repo at shawngmc/hubspace-ng: A python package to interface with the Afero Hubspace service for smart home devices (github.com)
  2. Run pip install --editable . to install dependencies
  3. Copy creds.json.template to creds.json and insert your username/password in the new file.
  4. Run python3 tools.py survey -a survey.zip to generate an anonymized report.
  5. (Optional but recommended) Open the zip file and make sure there is no data you consider sensitive. '-a' attempts to anonymize the data, removing geolocation data, wifi and bluetooth info, and device ids, but it may miss info on odd devices.
  6. Open a ticket in the git repo titled 'Survey from (USERNAME)' and attach the zip file.

I'll take a look at these and either close the ticket (as I suspect they'll be supported properly) or branch it into other tickets.

Thanks in advance!

shawngmc avatar Feb 08 '23 20:02 shawngmc

@shawngmc I have the survey.zip. Just to clarify, you want me to open a GitHub issue in the shawngmc/hubspace-ng repo and post it there, correct?

jasonhurlbert avatar Feb 09 '23 00:02 jasonhurlbert

@shawngmc I have the survey.zip. Just to clarify, you want me to open a GitHub issue in the shawngmc/hubspace-ng repo and post it there, correct?

Yes please - thanks!

shawngmc avatar Feb 09 '23 06:02 shawngmc

Sorry, I've been busy with a few things.

I think the Lock device type is ready. As far as I know, the only device type left is the Transformer type.

How do we want to try integrating the library?

shawngmc avatar Mar 23 '23 19:03 shawngmc

That is great. I think the transformer is just a collection of switches, does it need its own type? I think a good option is just to point people to your repo on my github and the forums. That way people can try yours and migrate to it. Better than breaking something that already works. I have no pride in ownership and I think your version will have a better chance of becoming an official version. I only have one light and a lock, I can test.

jdeath avatar Mar 23 '23 22:03 jdeath

I'd like to see the outlets listed as switches instead of lights so I don't have to convert all my other switches to lights to make a helper group. I have one outlet pair working (for some reason I can't seem to add anymore outlets thorough the Hubspace app) and a light socket switch but I have no Python experience as of yet. How can I help with adding the outlets as switches to your integration?

steveothesane avatar Jan 07 '24 10:01 steveothesane

There is no way in the integration because everything is done as a light, even locks, fans, etc. It would require a major refactor which I do not plan to do. There are some other forks out there where people have tried, but I do not think they are up to date.

If you click on a light, click on the gear icon, you change the "Show as" field to "outlet"

jdeath avatar Jan 07 '24 13:01 jdeath

Device Types have been implemented with #86 .

Expl0dingBanana avatar Jul 29 '24 19:07 Expl0dingBanana

I believe this has been resolved with 3.0. Please re-open the issue if the problem persists

Expl0dingBanana avatar Jul 31 '24 23:07 Expl0dingBanana