DavidMStraub / homeassistant-homeconnect

Custom component for Home Assistant to connect appliances supporting the Home Connect standard
MIT License
118 stars 29 forks source link

Home Appliance Events #42

Open JorSjo opened 4 years ago

JorSjo commented 4 years ago

Hi,

Thank you for integrating HomeConnect with HA, awesom work! I just upgraded and it works perfectly with HA 102.1.

This is a Wish and I would love to have an event sensor, if I knew more about Python and HA integrations, I would try to contribute with this myself. So I make a wish here, guess that there are more people who would like to get status messages to HA from HomeConnect. The part of the HomeConnect API I'm referring to is

Program Progress Events Home Appliance Events.

DavidMStraub commented 4 years ago

Hi,

actually I think the more challenging part is to understand what the API actually reports and how to properly represent it in HA, not the eventual coding. So if you can have a look at the logs for your devices and come up with a concrete suggestion I'd be happy to have a look.

The first thing I'd like to understand better: would it make more sense to have sensors mapped to each of these events, or rather firing acutal events in HA?

JorSjo commented 4 years ago

I guess firing events might be the right approach.

What I would like to do is, for example, get a message when water is not turned on to the dishwasher, or iDos is empty.

I'm not sure which logs you mean? Debug is on in my HA for homeconnect but I'm not sure how the architecture looks like? Does HomeConnect post HA when an event occurs or is it HA that polls Home connect for status?

When I understand what to do, I'm happy to contribute with some logs.

DavidMStraub commented 4 years ago

HA subscribes to an SSE stream for each appliance, i.e. it does not have to poll but receives push notifications. The events look like this:

{'LaundryCare.Dryer.Event.DryingProcessFinished':
  {
    'timestamp': 1575030757,
    'handling': 'acknowledge',
    'value': 'BSH.Common.EnumType.EventPresentState.Present', 
    'level': 'hint'
  }
}

The HA-HC integration keeps a dict for each appliance where the key/value pair is added to, i.e. it will contain a key

{'LaundryCare.Dryer.Event.DryingProcessFinished': 'BSH.Common.EnumType.EventPresentState.Present'}

This dictionary is logged for every event when you enable debug logging: https://github.com/DavidMStraub/homeassistant-homeconnect/blob/master/custom_components/homeconnect/api.py#L105-L107

So you could monitor that to understand how your device acts. Possibly all of this information is present in the API docs as well, but I'm not sure.

DavidMStraub commented 4 years ago

By the way: for the above example the key/value pair of the event will also show as a state attribute {'drying_process_finished': 'present'} of the dryer's power switch.

JorSjo commented 4 years ago

Perfect I found it 👍 Right now I don't get any updates from HomeConnect when the water is off, the only thing I get is. { 'timestamp': 1575098119, 'handling': 'none', 'uri': '/api/homeappliances/**************/status/BSH.Common.Status.OperationState', 'value': 'BSH.Common.EnumType.OperationState.Pause', 'level': 'hint' } I will check my settings on the developer site and When I integrate HA. Perhaps I missed something, when I get some data from HomeConnect I get back....

JorSjo commented 4 years ago

I've been sitting with postman trying to figure out the API from Home Connect simulator. Get /homeappliances/{haid}/events I don't know if its that part of the API you are using but I guess it would be great to use for firing events in HA.

The Events part is based on server-sent events, I've not been able to get postman to receive any updates or notifications from Home Connect more than It's listening to the event stream, with status 200. I found that Postman have some issues with SSE so I will try Curl and see if I can get any response there. Hoping for something like this when the water tank of the coffee machine gets empty. event: EVENT data: {"items":[{"key":"ConsumerProducts.CoffeeMaker.Event.WaterTankEmpty","timestamp":1479994113,"level":"warning","handling":"none","value":"BSH.Common.EnumType.EventPresentState.Present"}]} id: BOSCH-HCS06COM1-F8C8A682108B2A

JorSjo commented 4 years ago

I have successfully made a Get to the events part of Home Connect API. https://{{serverUrl}}/api/homeappliances/{{haid}}/events

I don't know if HA can receive Server-Sent events as a client, postman was not able to get anything from the respons, but cURL worked.

Hope this helps, and thank you for all the good work. If this is possible to implement it would be awesome as the update is instantly.

The cURL code is

curl -X GET   https://simulator.home-connect.com/api/homeappliances/BOSCH-HCS06COM1-0162782A8701/events   -H 'Accept: text/event-stream,text/event-stream'   -H 'Accept-Encoding: gzip, deflate'   -H 'Authorization: Bearer  here goes my Token...'   -H 'Cache-Control: no-cache'   -H 'Connection: keep-alive'   -H 'Host: simulator.home-connect.com'   -H 'cache-control: no-cache

And some responses from Home Connect

Door open event: NOTIFY

data: {"items":[{"level":"hint","handling":"none","key":"BSH.Common.Root.SelectedProgram","value":"ConsumerProducts.CoffeeMaker.Program.Beverage.Espresso","uri":"/api/homeappliances/BOSCH-HCS06COM1-0162782A8701/programs/selected","timestamp":1575708044}]}
id: BOSCH-HCS06COM1-0162782A8701

When the coffee is ready event: STATUS

data: {"items":[{"level":"hint","handling":"none","key":"BSH.Common.Status.OperationState","value":"BSH.Common.EnumType.OperationState.Finished","uri":"/api/homeappliances/BOSCH-HCS06COM1-0162782A8701/status/BSH.Common.Status.OperationState","timestamp":1575708075}]}
id: BOSCH-HCS06COM1-0162782A8701

Connected and Disconnected

event: DISCONNECTED
data:
id: BOSCH-HCS06COM1-0162782A8701

event: CONNECTED
data:
id: BOSCH-HCS06COM1-0162782A8701
DavidMStraub commented 4 years ago

Thanks, that's useful.

I don't know if HA can receive Server-Sent events as a client, postman was not able to get anything from the respons, but cURL worked.

Just to be clear: the Home Connect integration in Home Assistant is based on server-sent events, so the information is already there, it just has to be used.

JorSjo commented 4 years ago

Hi David,

Then what am I missing? I don't receive this messages in the debug log, and the remaining time is only updated in my HA every 60 second. Like its polling HomeConnect, for ex. the washing machine has still 45 seconds left when the program is finished.

May by I need to convert to Python so I can read your code to understand...

DavidMStraub commented 4 years ago

It would be great if you could look at the events returned when using the underlying Python library (and maybe compare it to what you see with your own method). Code snippet:

from homeconnect import HomeConnect
import webbrowser

CLIENT_ID = ... 
CLIENT_SECRET = ... 
REDIRECT_URI = ...

hc = HomeConnect(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI)
webbrowser.open(hc.get_authurl())

auth_result = input("Paste resulting URL here")
hc.get_token(auth_result)

def event_callback(appliance):
    print(appliance.status)

appl = hc.get_appliances()
for app in appl:
    app.listen_events(callback=event_callback)

The only caveat is that the printed status is not the event data alone, but a dictionary (appliance.status) which is updated with the event dictionary on every event received.

JorSjo commented 4 years ago

I had trouble getting Oauth to work with the simulator and your code, I used the simulator to test earlier. I have no response URL to use on the machine I'm testing on. Anyway, I wrote my own code where I use your SSEClient to make a test request. I was curious about getting any response from HC. I get events from the stream but not all that I get in Curl. Strange, maybe its my code, but I'll dig a little deeper when I get more time.

stigvi commented 4 years ago

I get a "alarm_clock_elapsed: present" attribute on the cooktop switch and would love to have this as an event in HA. Currently, I have to use IFTTT to get it as an event.

UksusoFF commented 3 years ago

Hi @DavidMStraub I'm also need events from dishwasher.

Trying to do actions described in upper comment have some issues:

  1. Authorize URL contains two slashes and can't be logged in here: https://api.home-connect.com//security/oauth/authorize
  2. After remove on slash auth success but got Invalid state response from HA
  3. After paste URL to input got oauthlib.oauth2.rfc6749.errors.MismatchingStateError and InsecureTransportError

What's wrong?

UksusoFF commented 3 years ago

Okay. Adding https version as second redirect url seems work. Now I see:

{'BSH.Common.Event.ProgramFinished': {'timestamp': 1620761044, 'handling': 'none', 'value': 'BSH.Common.EnumType.EventPresentState.Present', 'level': 'hint'}}
{'BSH.Common.Event.ProgramFinished': {'timestamp': 1620761044, 'handling': 'none', 'value': 'BSH.Common.EnumType.EventPresentState.Present', 'level': 'hint'}, 'BSH.Common.Setting.PowerState': {'timestamp': 1620761182, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/settings/BSH.Common.Setting.PowerState', 'value': 'BSH.Common.EnumType.PowerState.On', 'level': 'hint'}}
{'BSH.Common.Event.ProgramFinished': {'timestamp': 1620761044, 'handling': 'none', 'value': 'BSH.Common.EnumType.EventPresentState.Present', 'level': 'hint'}, 'BSH.Common.Setting.PowerState': {'timestamp': 1620761182, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/settings/BSH.Common.Setting.PowerState', 'value': 'BSH.Common.EnumType.PowerState.On', 'level': 'hint'}, 'BSH.Common.Root.SelectedProgram': {'timestamp': 1620761182, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/programs/selected', 'value': 'Dishcare.Dishwasher.Program.Eco50', 'level': 'hint'}}
{'BSH.Common.Event.ProgramFinished': {'timestamp': 1620761044, 'handling': 'none', 'value': 'BSH.Common.EnumType.EventPresentState.Present', 'level': 'hint'}, 'BSH.Common.Setting.PowerState': {'timestamp': 1620761182, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/settings/BSH.Common.Setting.PowerState', 'value': 'BSH.Common.EnumType.PowerState.On', 'level': 'hint'}, 'BSH.Common.Root.SelectedProgram': {'timestamp': 1620761182, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/programs/selected', 'value': 'Dishcare.Dishwasher.Program.Eco50', 'level': 'hint'}, 'BSH.Common.Option.ProgramProgress': {'timestamp': 1620761182, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/programs/selected/options/BSH.Common.Option.ProgramProgress', 'unit': '%', 'value': 0, 'level': 'hint'}}
{'BSH.Common.Event.ProgramFinished': {'timestamp': 1620761183, 'handling': 'none', 'value': 'BSH.Common.EnumType.EventPresentState.Off', 'level': 'hint'}, 'BSH.Common.Setting.PowerState': {'timestamp': 1620761182, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/settings/BSH.Common.Setting.PowerState', 'value': 'BSH.Common.EnumType.PowerState.On', 'level': 'hint'}, 'BSH.Common.Root.SelectedProgram': {'timestamp': 1620761182, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/programs/selected', 'value': 'Dishcare.Dishwasher.Program.Eco50', 'level': 'hint'}, 'BSH.Common.Option.ProgramProgress': {'timestamp': 1620761182, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/programs/selected/options/BSH.Common.Option.ProgramProgress', 'unit': '%', 'value': 0, 'level': 'hint'}}
{'BSH.Common.Event.ProgramFinished': {'timestamp': 1620761183, 'handling': 'none', 'value': 'BSH.Common.EnumType.EventPresentState.Off', 'level': 'hint'}, 'BSH.Common.Setting.PowerState': {'timestamp': 1620761182, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/settings/BSH.Common.Setting.PowerState', 'value': 'BSH.Common.EnumType.PowerState.On', 'level': 'hint'}, 'BSH.Common.Root.SelectedProgram': {'timestamp': 1620761182, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/programs/selected', 'value': 'Dishcare.Dishwasher.Program.Eco50', 'level': 'hint'}, 'BSH.Common.Option.ProgramProgress': {'timestamp': 1620761182, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/programs/selected/options/BSH.Common.Option.ProgramProgress', 'unit': '%', 'value': 0, 'level': 'hint'}, 'BSH.Common.Status.OperationState': {'timestamp': 1620761184, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/status/BSH.Common.Status.OperationState', 'value': 'BSH.Common.EnumType.OperationState.Ready', 'level': 'hint'}}
{'BSH.Common.Event.ProgramFinished': {'timestamp': 1620761183, 'handling': 'none', 'value': 'BSH.Common.EnumType.EventPresentState.Off', 'level': 'hint'}, 'BSH.Common.Setting.PowerState': {'timestamp': 1620761182, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/settings/BSH.Common.Setting.PowerState', 'value': 'BSH.Common.EnumType.PowerState.On', 'level': 'hint'}, 'BSH.Common.Root.SelectedProgram': {'timestamp': 1620761182, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/programs/selected', 'value': 'Dishcare.Dishwasher.Program.Eco50', 'level': 'hint'}, 'BSH.Common.Option.ProgramProgress': {'timestamp': 1620761182, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/programs/selected/options/BSH.Common.Option.ProgramProgress', 'unit': '%', 'value': 0, 'level': 'hint'}, 'BSH.Common.Status.OperationState': {'timestamp': 1620761184, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/status/BSH.Common.Status.OperationState', 'value': 'BSH.Common.EnumType.OperationState.Ready', 'level': 'hint'}, 'BSH.Common.Option.RemainingProgramTime': {'timestamp': 1620761186, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/programs/selected/options/BSH.Common.Option.RemainingProgramTime', 'unit': 'seconds', 'value': 13800, 'level': 'hint'}}
{'BSH.Common.Event.ProgramFinished': {'timestamp': 1620761183, 'handling': 'none', 'value': 'BSH.Common.EnumType.EventPresentState.Off', 'level': 'hint'}, 'BSH.Common.Setting.PowerState': {'timestamp': 1620761182, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/settings/BSH.Common.Setting.PowerState', 'value': 'BSH.Common.EnumType.PowerState.On', 'level': 'hint'}, 'BSH.Common.Root.SelectedProgram': {'timestamp': 1620761182, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/programs/selected', 'value': 'Dishcare.Dishwasher.Program.Eco50', 'level': 'hint'}, 'BSH.Common.Option.ProgramProgress': {'timestamp': 1620761182, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/programs/selected/options/BSH.Common.Option.ProgramProgress', 'unit': '%', 'value': 0, 'level': 'hint'}, 'BSH.Common.Status.OperationState': {'timestamp': 1620761184, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/status/BSH.Common.Status.OperationState', 'value': 'BSH.Common.EnumType.OperationState.Ready', 'level': 'hint'}, 'BSH.Common.Option.RemainingProgramTime': {'timestamp': 1620761186, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/programs/selected/options/BSH.Common.Option.RemainingProgramTime', 'unit': 'seconds', 'value': 13800, 'level': 'hint'}, 'BSH.Common.Status.DoorState': {'timestamp': 1620761187, 'handling': 'none', 'uri': '/api/homeappliances/400100521618005012/status/BSH.Common.Status.DoorState', 'value': 'BSH.Common.EnumType.DoorState.Open', 'level': 'hint'}}