Blue Connect pool measurements

Hi All,

Here is the updated Node-Red JSON for my inbound data flow…

[{"id":"a2345807.bbc9c8","type":"ha-webhook","z":"1bb50542.81126b","name":"BlueConnect Webhook","server":"a23a4d01.eeb32","outputs":1,"webhookId":"blue_connect","payloadLocation":"payload","payloadLocationType":"msg","headersLocation":"","headersLocationType":"none","x":180,"y":320,"wires":[["ebc5b5a.3c2a248"]]},{"id":"ebc5b5a.3c2a248","type":"switch","z":"1bb50542.81126b","name":"New Measure?","property":"payload.time","propertyType":"msg","rules":[{"t":"neq","v":"","vt":"prev"}],"checkall":"true","repair":false,"outputs":1,"x":400,"y":320,"wires":[["d2c85e6f.f164e","3770976e.784fb8","5f5d6f7f.8c305","dae8675e.10b038","747b5a26.135d64","b048c2c3.9025d","7d0176e9.094a18"]]},{"id":"d2c85e6f.f164e","type":"function","z":"1bb50542.81126b","name":"x1000","func":"var x=Number(msg.payload.salinity)\nmsg.payload.salinity=x*1000\nreturn msg;","outputs":1,"noerr":0,"x":650,"y":360,"wires":[["f38fab54.5fe968"]]},{"id":"3770976e.784fb8","type":"change","z":"1bb50542.81126b","name":"Measure Delay","rules":[{"t":"set","p":"payload","pt":"msg","to":"(\t   $toMillis($now()) - $toMillis(\t       payload.time,\t       '[D01]/[M01]/[Y0001] [H01]:[m01]:[s01]' \t   )\t)/1000\t","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":540,"y":480,"wires":[["a256dbf0.03bb48"]]},{"id":"6424dda6.4cc674","type":"ha-entity","z":"1bb50542.81126b","name":"Blue Connect Measurement Delay","server":"a23a4d01.eeb32","version":1,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Blue Connect Measurement Delay"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":"s"}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","x":1020,"y":480,"wires":[[]]},{"id":"5f5d6f7f.8c305","type":"ha-entity","z":"1bb50542.81126b","name":"Temperature","server":"a23a4d01.eeb32","version":1,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"pool_temperature"},{"property":"device_class","value":"temperature"},{"property":"icon","value":""},{"property":"unit_of_measurement","value":"°C"}],"state":"payload.temperature","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"msg","inputOverride":"allow","x":790,"y":180,"wires":[[]]},{"id":"dae8675e.10b038","type":"ha-entity","z":"1bb50542.81126b","name":"pH","server":"a23a4d01.eeb32","version":1,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"pool_ph"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":"pH"}],"state":"payload.ph","stateType":"msg","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","x":770,"y":240,"wires":[[]]},{"id":"747b5a26.135d64","type":"ha-entity","z":"1bb50542.81126b","name":"Orp","server":"a23a4d01.eeb32","version":1,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"pool_orp"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":"mV"}],"state":"payload.orp","stateType":"msg","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","x":770,"y":300,"wires":[[]]},{"id":"f38fab54.5fe968","type":"ha-entity","z":"1bb50542.81126b","name":"Salinity","server":"a23a4d01.eeb32","version":1,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"pool_salinity"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":"ppm"}],"state":"payload.salinity","stateType":"msg","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","x":780,"y":360,"wires":[[]]},{"id":"b048c2c3.9025d","type":"ha-entity","z":"1bb50542.81126b","name":"Conductivity","server":"a23a4d01.eeb32","version":1,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"pool_conductivity"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":"mho"}],"state":"payload.conductivity","stateType":"msg","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","x":790,"y":420,"wires":[[]]},{"id":"2e3b8fff.7ed07","type":"ha-entity","z":"1bb50542.81126b","name":"Update Count","server":"a23a4d01.eeb32","version":1,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Blue Connect Update Count"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","x":800,"y":540,"wires":[[]]},{"id":"7d0176e9.094a18","type":"api-current-state","z":"1bb50542.81126b","name":"Count","server":"a23a4d01.eeb32","version":1,"outputs":1,"halt_if":"","halt_if_type":"num","halt_if_compare":"is","override_topic":false,"entity_id":"sensor.blue_connect_update_count","state_type":"num","state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","blockInputOverrides":false,"x":490,"y":540,"wires":[["b94912c.85ab7f"]]},{"id":"b94912c.85ab7f","type":"function","z":"1bb50542.81126b","name":"+1","func":"var x=Number(msg.payload)\nmsg.payload=x+1\nreturn msg;","outputs":1,"noerr":0,"x":630,"y":540,"wires":[["2e3b8fff.7ed07"]]},{"id":"88995690.f6b7b8","type":"inject","z":"1bb50542.81126b","name":"Reset Counter","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"00 00 * * *","once":false,"onceDelay":0.1,"x":160,"y":600,"wires":[["5230267f.9a7e68"]]},{"id":"a256dbf0.03bb48","type":"function","z":"1bb50542.81126b","name":"Single Decimal Place","func":"var x = Number(msg.payload)\n\nmsg.payload = x.toFixed(1)\nreturn msg;","outputs":1,"noerr":0,"x":760,"y":480,"wires":[["6424dda6.4cc674"]]},{"id":"c22f216.ef67ae","type":"ha-entity","z":"1bb50542.81126b","name":"Yesterday Count","server":"a23a4d01.eeb32","version":1,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Blue Connect Updates Yesterday"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","x":480,"y":600,"wires":[["8215815e.5dfc2"]]},{"id":"5230267f.9a7e68","type":"api-current-state","z":"1bb50542.81126b","name":"Count","server":"a23a4d01.eeb32","version":1,"outputs":1,"halt_if":"","halt_if_type":"num","halt_if_compare":"is","override_topic":false,"entity_id":"sensor.blue_connect_update_count","state_type":"num","state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","blockInputOverrides":false,"x":330,"y":600,"wires":[["c22f216.ef67ae"]]},{"id":"8215815e.5dfc2","type":"change","z":"1bb50542.81126b","name":"Zero","rules":[{"t":"set","p":"payload","pt":"msg","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":630,"y":600,"wires":[["2e3b8fff.7ed07"]]},{"id":"a23a4d01.eeb32","type":"server","z":"","name":"Home Assistant"}]

One thing we noticed when I was helping a friend set his up using my exported JSON, is that for the HA nodes, we needed to go in and change the server name from “Home Assistant” to “Home Assistant”!!
I’m assuming there is some hidden id in play, and the imported “Home Assistant” which was selected was not the correct one.
The flow now looks like this…


It depends on having not just the node red addon installed, but also the integration installed (via HACS) and configured. I no longer use the “input-numbers” as NR can now create sensors directly in HA which is great.
As a previous poster mentioned, after deploying this flow, you’ll need to go into HA config and find the webhook that has been created. I use Nabu Casa cloud for this inbound webhook so it’s auto-created, but you could also port-map your HA server from the outside world.
Hope that helps

Hey thank you @rzulian and @danps.

I’m still struggling with my skills and understanding of the solution but it is becoming clearer for me now. Cheers.

The IFTTT part looks to be working but my automation doesn’t seem to have been triggered.

I’m assuming my casa URL below is doing the same thing in calling my HA server:

My automation.blue_connect_data_update shows last_triggered: null and there aren’t any instances of webhook or IFTTT in my log.

The automation I have was from dan’s post above which looks inline with the advice from Riccardo:

- id: blue_connect_data_update
  alias: Blue Connect Data Update
  trigger:
  - platform: webhook
    webhook_id: blueconnect
  action:
  - service: input_number.set_value
    data_template:
      entity_id: input_number.pool_temperature
      value: '{{trigger.json.temperature | float}}'

Any ideas appreciated.

Should I stick with the input-number or try the node-red method? Concerned that it may further stretch my ability.

Thanks!!

Hi,

On the product page it says that it can communicate via bluetooth, does someone tried to scan the data advertised by BLE?
This would enable a more direct integration.

@thetastate Did you check if this is triggering the automation?
curl -H 'Content-Type: application/json' -X POST -d '{ "temperature":"16.4" }' https://hooks.nabu.casa/everything-else
@1technophile I’ve no idea on how to scan the data advertised by BLE. If you can suggest me how to do it I can try. In any case, if the Blueconnect is in the pool, it can be difficult to read it via Bluetooth. They are also selling a Bluetooth extender via wifi, but it’s not clear if you can control the extender and request more readings. I suspect they have limited readings to preserve battery life.

You may try to scan the device with a bluetooth app and see if it advertise service data like below:

If it is the case, there is a possibility that we could use these data directly from the sensor.

I am quite certain that this would be possible, as I can use my iPhone to request and receive a reading. The phone and blue connect communicates over Bluetooth. But has someone experience for how to understand Bluetooth protocols? Is there a Bluetooth “hub” that integrates with Home Assistant?

1 Like

You can use either the embedded bluetooth chip of a Pi or an ESP32

Yes I have

I’ve just checked. It is advertising services

Cool! I assume a BLE integration needs to firstly send a command to the blue connect to perform a reading and then listen to it. Good thing that using BLE would allow for custom intervals of the reading polls, eg, every 30 mins instead of approx hourly with sigfox.

If you scroll down do you see some fields called “service data” like in my example?

Thanks @rzulian and @danps

All working now.

It turns out that I needed to enable the blue connect webhook in Configuration > Home Assistant Cloud > Webhooks > Blue Connect Data Update (automation).

This is what I’ve got with another app

Hi guys. I also acquired a Blue Connect, but I took a different route to getting data out. I’ve reversed their apps API.

I’ve created a BlueRiiot -> MQTT program and placed it here: https://github.com/LordMike/MBW.BlueRiiot2MQTT

Let me know in the issues if something is amiss…

Mike.

9 Likes

I’m trying to make this work with IFTTT. I think I have everything set up properly; I get communication both ways between HASS and IFTTT and my sensors are all defined and visible in HASS. My problem may be with automation:

- id: blue_connect_data_update
  alias: SERVICES - Blue Connect Data Update
  trigger:
  - platform: event
    event_type: ifttt_webhook_received
    event_data:
      action: blueconnect
  condition: []
  action:
  - service: input_number.set_value
    data_template:
      entity_id: input_number.pool_temperature
      value: '{{trigger.json.temperature | float}}'
  - service: input_number.set_value
    data_template:
      entity_id: input_number.pool_ph
      value: '{{trigger.json.ph | float}}'
  - service: input_number.set_value
    data_template:
      entity_id: input_number.pool_orp
      value: '{{trigger.json.orp | float}}'
  - service: input_number.set_value
    data_template:
      entity_id: input_number.pool_salinity
      value: '{{trigger.json.salinity | float}}'
  - service: input_number.set_value
    data_template:
      entity_id: input_number.pool_conductivity
      value: '{{trigger.json.conductivity | float}}'

I get the following error message after a reading:

Log Details (ERROR)
Logger: homeassistant.components.automation
Source: helpers/service.py:135
Integration: Automation (documentation, issues)
First occurred: 9:59:06 PM (1 occurrences)
Last logged: 9:59:06 PM

SERVICES - Blue Connect Data Update: Error executing script. Unexpected error for call_service at pos 1: Error rendering data template: UndefinedError: 'dict object' has no attribute 'json'
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 222, in async_render
    return compiled.render(kwargs).strip()
  File "/usr/local/lib/python3.7/site-packages/jinja2/environment.py", line 1090, in render
    self.environment.handle_exception()
  File "/usr/local/lib/python3.7/site-packages/jinja2/environment.py", line 832, in handle_exception
    reraise(*rewrite_traceback_stack(source=source))
  File "/usr/local/lib/python3.7/site-packages/jinja2/_compat.py", line 28, in reraise
    raise value.with_traceback(tb)
  File "<template>", line 1, in top-level template code
  File "/usr/local/lib/python3.7/site-packages/jinja2/sandbox.py", line 407, in getattr
    value = getattr(obj, attribute)
jinja2.exceptions.UndefinedError: 'dict object' has no attribute 'json'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 132, in async_prepare_call_from_config
    template.render_complex(config[CONF_SERVICE_DATA_TEMPLATE], variables)
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 71, in render_complex
    return {key: render_complex(item, variables) for key, item in value.items()}
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 71, in <dictcomp>
    return {key: render_complex(item, variables) for key, item in value.items()}
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 73, in render_complex
    return value.async_render(variables)
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 224, in async_render
    raise TemplateError(err)
homeassistant.exceptions.TemplateError: UndefinedError: 'dict object' has no attribute 'json'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 153, in _async_step
    self, f"_async_{cv.determine_script_action(self._action)}_step"
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 623, in _async_call_service_step
    *self._prep_call_service_step(), blocking=True, context=self._context
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 252, in _prep_call_service_step
    return async_prepare_call_from_config(self._hass, self._action, self._variables)
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 135, in async_prepare_call_from_config
    raise HomeAssistantError(f"Error rendering data template: {ex}") from ex
homeassistant.exceptions.HomeAssistantError: Error rendering data template: UndefinedError: 'dict object' has no attribute 'json'
Connection lost. Reconnecting…

Any idea?

This is my IFTTT trigger, which properly get fired when a new measure is taken. I do receive the event in HA.

One thing I noticed is that I do not get any entities listed under my IFTTT integration in HA. Should I be getting something there?

image

image

UPDATE:

Ok, I got it to work finally by simply replacing “json” by “event.data”. For example, from

value: '{{trigger.json.temperature | float}}'

to

value: '{{trigger.event.data.temperature | float}}'

UPDATE 2: End Result:

1 Like

Great to hear you have it working. And nice Lovelace implementation! FYI, I also don’t have any entities in the IFTTT integration. Seems to work well without this.

1 Like

Hi @Madelinot
Loving the layout as well!
Out of curiosity, what are you using for the water level measurement?

@danps I am using a custom made contraption that is attached to my pool ladder. It’s actually hard to notice; you have to look for it once installed. It’s a 1" tube/pipe (about 8" long) in which I insert a floating magnet. The other half of the pipe contains the sensor in a sealed compartment. When the magnet reaches the sensor, the level is normal. If the magnet is out of contact with the sensor, water level is low. It’s really simple. I used an AeonLabs recessed z-wave door sensor (zw089) that I inserted in the tube (I cut the two little plastic wings). I also glued a 2" piece of foam on the magnet to make it float inside the tube. The sensor is actually out of the water in a sealed portion of the tube, in which I filled the remaining space with silica gel (Dry&Dry) to absorb any humidity that could seep in.
This is the sensor I used:
https://aeotec.com/hidden-z-wave-door-sensor/, available on Amazon: https://www.amazon.com/Recessed-Invisible-Security-SmartStart-Required/dp/B082PT71MM/
I can take some picture if you want. Cheers,

2 Likes