homeassistant-grohe_sense icon indicating copy to clipboard operation
homeassistant-grohe_sense copied to clipboard

Grohe blue integration

Open motaker opened this issue 4 years ago • 24 comments

Hi, first of all Thank you for your this great work !

I am just wondering is it also possible to integrate Grohe blue product which is appeared in Ondus app? Grohe Blue Home/Professional is able to control water on/off(still, sparkling, strong sparkling) and the amount.

API discussion has been made already here. https://github.com/FlorianSW/grohe-ondus-api-java/issues/12

motaker avatar Jun 11 '20 13:06 motaker

Happy you like the project, and thanks for the pointer. Unfortunately, I'm unlikely to add support for Grohe Blue as I don't have one myself, and Grohe offers no development support (documentation, simulators, et.c.). Would be happy to accept pull requests if someone has a Blue and wants to try their hand at it though.

gkreitz avatar Jul 15 '20 18:07 gkreitz

Hello , I have such a system and would like to help to get the blue system in Home Assistant up and running. Here is the API discussion. https://github.com/FlorianSW/grohe-ondus-api-java/issues/12

I could like to test the release and help out a bit if there are bugs

Buktahula avatar May 03 '21 16:05 Buktahula

I can help on this topic...at least to provide some details:

Those are the methods: @p("/v3/iot/locations/{locationId}") @p("/v3/iot/locations/{locationId}/rooms/{roomId}") @o("/v3/iot/locations") @p("/v3/iot/locations/{locationId}/storage") @b("/v3/iot/locations/{locationId}") @f("/v3/iot/locations/{locationId}/storage") @b("/v3/iot/locations/{locationId}/rooms/{roomId}") @o("/v3/iot/locations/{locationId}/rooms") @o("/v3/iot/locations/{locationId}/rooms/{roomId}/appliances")

The interesting part is...when we request "rooms" there are 2 rooms. The 2nd room contains the information of the Blue Home:

[ { "appliance_id": "7722d243-2652-4359-a27a-b529b06eb37b", "installation_date": "2021-09-01T21:24:55.000+00:00", "name": "My GROHE Blue Home", "serial_number": "33356764", "type": 104, "version": "01.00.Z10.0300.0104", "tdt": "2021-09-24T09:58:07.000+02:00", "timezone": 60, "config": { "co2_type": 1, "hose_length": 87, "co2_consumption_medium": 48, "co2_consumption_carbonated": 65, "guest_mode_active": false, "auto_flush_active": false, "flush_confirmed": false, "f_parameter": 9, "l_parameter": 1, "flow_rate_still": 20, "flow_rate_medium": 25, "flow_rate_carbonated": 20 }, "role": "owner", "registration_complete": true, "presharedkey": "feCxi+9Rj3Pt8NfWbh7wpf+S+ACcSCURvI6dfZihWIs=", "params": { "water_hardness": 0, "carbon_hardness": 6, "filter_type": 1, "variant": 4, "auto_flush_reminder_notif": true, "consumables_low_notif": true, "product_information_notif": true }, "error": { "errors_1": false, "errors_2": false, "errors_3": false, "errors_4": false, "errors_5": false, "errors_6": false, "errors_7": false, "errors_8": false, "errors_9": false, "errors_10": false, "errors_11": false, "errors_12": false, "errors_13": false, "errors_14": false, "errors_15": false, "errors_16": false, "error1_counter": 256, "error2_counter": 256, "error3_counter": 256, "error4_counter": 0, "error5_counter": 0, "error6_counter": 0, "error7_counter": 0, "error8_counter": 0, "error9_counter": 0, "error10_counter": 0, "error11_counter": 0, "error12_counter": 3840, "error13_counter": 0, "error14_counter": 0, "error15_counter": 0, "error16_counter": 0 }, "state": { "start_time": 1632394679, "APPLIANCE_SUCCESSFUL_CONFIGURED": false, "co2_empty": false, "co2_20l_reached": true, "filter_empty": false, "filter_20l_reached": false, "cleaning_mode_active": false, "cleaning_needed": false, "flush_confirmation_required": false, "System_error_bitfield": 0 } } ]

@gkreitz Unfortunately I don't know how to code this part in python. If you need any help I can support. I'm a Java developer.

darkm20 avatar Sep 24 '21 09:09 darkm20

I'm also happy to help with my Grohe Blue

cg089 avatar Oct 19 '21 16:10 cg089

I'm also happy to help with my Grohe Blue

need somebody who has knowledge with python...

darkm20 avatar Oct 19 '21 16:10 darkm20

I would love this feature to be implemented ;-)

JakobTewes avatar Feb 17 '22 12:02 JakobTewes

Same for me, would love to have that possibility!

firstusing avatar Oct 01 '22 20:10 firstusing

i would also like to get and support this.

gnoffer avatar Oct 10 '22 13:10 gnoffer

I have started development for Blue Home. Unfortunately I'm far from a python developer, so I'm struggling very hard to understand the code :(

Anyway my initial attempt is in my fork: MortenVinding/homeassistant-grohe_sense

For now it only adds some sensors for the Blue Home, but last time I looked at this (more than a year ago) I at least had a rudimentary support to tap water. Now I just don't remember what I did :(

My goal is to have automations to tap predefined amounts of water, so I can have a small panel next to the tap, with buttons to fill a 1L carafe with still or carbonated water.

You are all more than welcome to add to my code! ;)

MortenVinding avatar Oct 20 '22 22:10 MortenVinding

Hi guys, I am new to Home Assistant and GitHub, and it has been years since I last coded (I know, the perfect trifecta of incompetence). However, I am also the owner of a Grohe Blue and am happy to learn. If you need someone to test anything, please reach out. From a feature perspective, my interest is to understand the state of the filter (next filter change, next cleaning, or last change/cleaning) and the state of the CO2 tank.

dubmaker avatar Nov 02 '22 14:11 dubmaker

as you dont have the function to discuss on your gitrepo @MortenVinding - i tried it and for the beginning, the sensors work for my Grohe Blue Home

image

when i push the "valve" button it immediately starts to spend still water but did not stop

gnoffer avatar Nov 02 '22 14:11 gnoffer

one Day later, i got:

Error during setup of component grohe_sense 07:13:53 – (FEHLER) Grohe Sense (benutzerdefinierte Integration) Grohe sense refresh token is invalid (or expired), please update your configuration with a new refresh token 07:13:53 – (FEHLER) Grohe Sense (benutzerdefinierte Integration)

gnoffer avatar Nov 03 '22 10:11 gnoffer

as you dont have the function to discuss on your gitrepo @MortenVinding - i tried it and for the beginning, the sensors work for my Grohe Blue Home

Sorry I'm a bit of a GitHub noob Discussions and issues is enabled now :)

when i push the "valve" button it immediately starts to spend still water but did not stop

I should stop after 20ml. at least it does for me 🤷

MortenVinding avatar Nov 03 '22 10:11 MortenVinding

one Day later, i got:

Error during setup of component grohe_sense 07:13:53 – (FEHLER) Grohe Sense (benutzerdefinierte Integration) Grohe sense refresh token is invalid (or expired), please update your configuration with a new refresh token 07:13:53 – (FEHLER) Grohe Sense (benutzerdefinierte Integration)

there seems to be general problems with refreshing. usually works for me if I restart HA. not ideal I know, but I hardly understand what's going on in the main part of this integration, so I'm afraid I will be no help in solving that. Hopefully @gkreitz will get to the bottom of that if he finds the time.

MortenVinding avatar Nov 03 '22 10:11 MortenVinding

Hi guys, I am new to Home Assistant and GitHub, and it has been years since I last coded (I know, the perfect trifecta of incompetence). However, I am also the owner of a Grohe Blue and am happy to learn. If you need someone to test anything, please reach out. From a feature perspective, my interest is to understand the state of the filter (next filter change, next cleaning, or last change/cleaning) and the state of the CO2 tank.

All you help is greatly appreciated! :) As i say, my knowledge about programming as a whole, and python i particular, is very limited. So if you have the skills to move on with this, I think many of us would be VERY happy :)

MortenVinding avatar Nov 03 '22 10:11 MortenVinding

Have anyone tried to reverse engineer the wires between the faucet and the carbonator? There are four wires, red/black, which I presume are power, and yellow/blue, which probably are some communication protocol. If one could find out how they speak, it would be easy to put a ESP in between. That way you could control all water flow, and also get alerts from the blinking light. That way everything is local, without having to send messages to Germany and back to fill a bottle.

erikkt avatar Jan 10 '23 07:01 erikkt

That way everything is local, without having to send messages to Germany and back to fill a bottle.

Good idea. Although I think I would be easier and less destructive to use bluetooth if you goal is to avoid the cloud.

MortenVinding avatar Jan 10 '23 20:01 MortenVinding

Perhaps, but my older version doesn't have bluetooth/WiFi. Even so, it's not very destructive to cut a four wire cable.

erikkt avatar Jan 10 '23 20:01 erikkt

I really wanted a button for filling up a jug with soda water and stop when full, and I hate cloud services in home automation. So I did a little hacking in my Blue. Found out which relay that controlled soda water and then attached an ESP relay to it. Now I have a zigbee button that, when pushed, supplies soda water for x amount of seconds and then stops. If anyone else needs it, the hack is quite simple. The ESP releay NO is connected via the blue wires to the solder points. If you want to power the ESP internally, there is unfortunately only 24 VAC available, so you'll need a converter. The supply is available where the white wires are soldered. I'm using this converter, works good: https://de.aliexpress.com/item/1005004924798895.html?gatewayAdapt=glo2deu Just remember to adjust correct voltage via the little pot meter.

2023-02-22 18 22 35

erikkt avatar Feb 23 '23 06:02 erikkt

hello, following this thread for my grohe blue home, I finished doing another way 1st I found the location,room,appliance id with postman and manually

in config.yaml:

I created a command-line sensor to refresh token
command_line:
  - sensor:
      name: py3_grohe_refreshtoken
      unique_id: py3_grohe_refreshtoken
      scan_interval: 7689600 #any high interval
      command: "python3 /config/myscripts/pythonrequest.py"
      json_attributes:
        - access_token
        - expires_in
        - refresh_expires_in
        - refresh_token
      value_template: "{{ now() + timedelta(seconds = value_json.expires_in)}}"

/config/myscripts/pythonrequest.py

import requests
import json
import sys
import re

url = "https://idp2-apigw.cloud.grohe.com/v3/iot/oidc/refresh"
with open('/config/secrets.yaml', 'r') as secretfile:
    data = secretfile.readlines()
for line in data:
    if 'grohe_current_refresh_token' in line:
        refreshtoken = line.split('"')[1]
        if ('Bearer' in refreshtoken):
            refreshtoken = refreshtoken.split(' ')[1]
payload = json.dumps({ "refresh_token": refreshtoken})
headers = {'Content-Type': 'application/json'}
response = requests.request("POST", url, headers=headers, data=payload)
parsed_json = json.loads(response.text)
newactiv = parsed_json['access_token']
newrefresh = parsed_json['refresh_token']

with open('/config/secrets.yaml', 'r') as secretfile:
    data = secretfile.readlines()
new_data = []
for line in data:
    if 'grohe_current_activ_token' in line:
        new_data.append(f'grohe_current_activ_token: Bearer {newactiv}\n')
    elif 'grohe_current_refresh_token' in line:
        new_data.append(f'grohe_current_refresh_token: "{newrefresh}"\n')
    else:
        new_data.append(line)

with open('/config/secrets.yaml', 'w') as file:
    file.writelines(new_data)

print (response.text)

and a rest command to run water in config.yaml:

rest_command:
  grohe_runwater_command:
    url: https://idp2-apigw.cloud.grohe.com/v3/iot/locations/[MYID]/rooms/[MYROOMID]/appliances/[myapplianceID]/command
    method: "POST"
    headers:
      Authorization: Bearer {{ state_attr('sensor.py3_grohe_refreshtoken','access_token') }}
    content_type: "application/json"
    payload: '{"command": {"co2_status_reset": false,"tap_type":{{int(states("input_number.watertype"))}},"cleaning_mode": false,"filter_status_reset": false,"get_current_measurement": true,"tap_amount":{{int(states("input_number.waterquantity"))}},"factory_reset": false,"revoke_flush_confirmation": false,"exec_auto_flush": false}}'

I also created 2input_numbers: input_number.watertype which can be 1 for still, 3 for sparkling and 2 for half and input_number.waterquantity for the quantity in ml with minimum 50

and then an automation in the UI like:

trigger: on quantity changed to a number between 50 and 2000
conditions: type is not 0 and qty is more than 50
actions:
condition action: 
{% if as_local(states('sensor.py3_grohe_refreshtoken')| as_datetime) <= now()%}
true
{% else %}
false
{%- endif %}
then call py3_grohe_refreshtoken entity

then call grohe_runwater_command service
and finally set watertype and quantity to 0

or my yaml:

alias: testpour
description: ""
trigger:
  - platform: numeric_state
    entity_id:
      - input_number.waterquantity
    above: 50
    below: 9999999
condition:
  - condition: not
    conditions:
      - condition: state
        entity_id: input_number.watertype
        attribute: initial
        state: "0"
  - condition: not
    conditions:
      - condition: numeric_state
        entity_id: input_number.waterquantity
        attribute: initial
        above: 0
        below: 50
action:
  - if:
      - condition: template
        value_template: >-
          {% if as_local(states('sensor.py3_grohe_refreshtoken')| as_datetime)
          <= now()%}
          true
          {% else %}
          false
          {%- endif %}
    then:
      - service: switch.turn_on
        target:
          entity_id: switch.py3_notify_grohe_refreshtoken
        data: {}
        enabled: false
      - service: homeassistant.update_entity
        target:
          entity_id: sensor.py3_grohe_refreshtoken
        data: {}
  - delay:
      hours: 0
      minutes: 0
      seconds: 0
      milliseconds: 100
  - service: rest_command.grohe_runwater_command
    data: {}
  - service: input_number.set_value
    target:
      entity_id:
        - input_number.watertype
        - input_number.waterquantity
      device_id: []
      area_id: []
    data:
      value: 0
mode: single

finally any automation like when click on smartbutton, set water to 1 and qty to 500ml

Greencollision avatar Jan 19 '24 21:01 Greencollision

Heyhey @Greencollision,

can you give me (and surely others) a favor and work over your posts formatting? This would significantly increase readability :-)

JakobTewes avatar Jan 26 '24 16:01 JakobTewes

Interesting approach @Greencollision !

Certainly solves my biggest problem which is how to get the value of a number entity in to the integration.

I will definitely take a look at this once I get the time.

MortenVinding avatar Jan 26 '24 19:01 MortenVinding

ciao, seguendo questo thread per la mia casa grohe blue, ho finito di fare un altro modo prima ho trovato la posizione, la stanza, l'ID dell'apparecchio con il postino e manualmente

nel file config.yaml:

I created a command-line sensor to refresh token
command_line:
  - sensor:
      name: py3_grohe_refreshtoken
      unique_id: py3_grohe_refreshtoken
      scan_interval: 7689600 #any high interval
      command: "python3 /config/myscripts/pythonrequest.py"
      json_attributes:
        - access_token
        - expires_in
        - refresh_expires_in
        - refresh_token
      value_template: "{{ now() + timedelta(seconds = value_json.expires_in)}}"

/config/myscripts/pythonrequest.py

import requests
import json
import sys
import re

url = "https://idp2-apigw.cloud.grohe.com/v3/iot/oidc/refresh"
with open('/config/secrets.yaml', 'r') as secretfile:
    data = secretfile.readlines()
for line in data:
    if 'grohe_current_refresh_token' in line:
        refreshtoken = line.split('"')[1]
        if ('Bearer' in refreshtoken):
            refreshtoken = refreshtoken.split(' ')[1]
payload = json.dumps({ "refresh_token": refreshtoken})
headers = {'Content-Type': 'application/json'}
response = requests.request("POST", url, headers=headers, data=payload)
parsed_json = json.loads(response.text)
newactiv = parsed_json['access_token']
newrefresh = parsed_json['refresh_token']

with open('/config/secrets.yaml', 'r') as secretfile:
    data = secretfile.readlines()
new_data = []
for line in data:
    if 'grohe_current_activ_token' in line:
        new_data.append(f'grohe_current_activ_token: Bearer {newactiv}\n')
    elif 'grohe_current_refresh_token' in line:
        new_data.append(f'grohe_current_refresh_token: "{newrefresh}"\n')
    else:
        new_data.append(line)

with open('/config/secrets.yaml', 'w') as file:
    file.writelines(new_data)

print (response.text)

e un comando rest per eseguire l'acqua in config.yaml:

rest_command:
  grohe_runwater_command:
    url: https://idp2-apigw.cloud.grohe.com/v3/iot/locations/[MYID]/rooms/[MYROOMID]/appliances/[myapplianceID]/command
    method: "POST"
    headers:
      Authorization: Bearer {{ state_attr('sensor.py3_grohe_refreshtoken','access_token') }}
    content_type: "application/json"
    payload: '{"command": {"co2_status_reset": false,"tap_type":{{int(states("input_number.watertype"))}},"cleaning_mode": false,"filter_status_reset": false,"get_current_measurement": true,"tap_amount":{{int(states("input_number.waterquantity"))}},"factory_reset": false,"revoke_flush_confirmation": false,"exec_auto_flush": false}}'

Ho creato anche 2input_numbers: input_number.watertype che può essere 1 per fermo, 3 per frizzante e 2 per mezzo e input_number.waterquantity per la quantità in ml con minimo 50

e poi un'automazione nell'interfaccia utente come:

trigger: on quantity changed to a number between 50 and 2000
conditions: type is not 0 and qty is more than 50
actions:
condition action: 
{% if as_local(states('sensor.py3_grohe_refreshtoken')| as_datetime) <= now()%}
true
{% else %}
false
{%- endif %}
then call py3_grohe_refreshtoken entity

then call grohe_runwater_command service
and finally set watertype and quantity to 0

o il mio yaml:

alias: testpour
description: ""
trigger:
  - platform: numeric_state
    entity_id:
      - input_number.waterquantity
    above: 50
    below: 9999999
condition:
  - condition: not
    conditions:
      - condition: state
        entity_id: input_number.watertype
        attribute: initial
        state: "0"
  - condition: not
    conditions:
      - condition: numeric_state
        entity_id: input_number.waterquantity
        attribute: initial
        above: 0
        below: 50
action:
  - if:
      - condition: template
        value_template: >-
          {% if as_local(states('sensor.py3_grohe_refreshtoken')| as_datetime)
          <= now()%}
          true
          {% else %}
          false
          {%- endif %}
    then:
      - service: switch.turn_on
        target:
          entity_id: switch.py3_notify_grohe_refreshtoken
        data: {}
        enabled: false
      - service: homeassistant.update_entity
        target:
          entity_id: sensor.py3_grohe_refreshtoken
        data: {}
  - delay:
      hours: 0
      minutes: 0
      seconds: 0
      milliseconds: 100
  - service: rest_command.grohe_runwater_command
    data: {}
  - service: input_number.set_value
    target:
      entity_id:
        - input_number.watertype
        - input_number.waterquantity
      device_id: []
      area_id: []
    data:
      value: 0
mode: single

infine qualsiasi automazione come quando si fa clic sullo smartbutton, si imposta l'acqua su 1 e la quantità su 500 ml

Thanks for your work, could you just tell me how to find the location, room, device ID with the postman and manually?

Asino123 avatar Mar 12 '24 13:03 Asino123

@Asino123 the link and the info you want are there https://github.com/gkreitz/homeassistant-grohe_sense/issues/5#issuecomment-831384828

Greencollision avatar Apr 08 '24 19:04 Greencollision