-
Notifications
You must be signed in to change notification settings - Fork 97
Home Assistant Setup Instructions
These instructions are provided courtesy of @sonapsent
The following shows how nodejs-poolController can be integrated into Home Assistant. This allows everything smart home related to be controlled from a central platform and provide additional local automation for a swimming pool. After setup it is possiable to create notifcations, view historical data/graphs, or even connect to voice services like Google or Alexa within Home Assistant.
Disclaimer: Myself and others involved in nodejs-poolController are not responsiable for damage to equipment, thermonuclear war, or other harm to personnel. Controlling industrial equipment is serious so please monitor the system and thoroughly test your setup.
- Controller: [e.g. Nixie Single Body (nodejs-PC v7.2)]
- 30,000 Gallon In-Ground Pool
- Pump manufacturer and model: [e.g. V-Green 165 VS Motor / Stealth Pump, relay control]
- Filter: [Pressure Gauge]
- Temperature Sensors: [ 10k thermistors for water and air]
- Chemical controller: [e.g. REMChem, Atlas EZO ORP and PH]
- Heater(s): [e.g. Heatpump, relay control]
- Chlorinator: [e.g. Aquarite 900, RS485]
The instructions below assume that both nodejs-PoolController and Home Assistant are setup and running independently. Please ensure that pool devices are working within the web based dashPanel before continuing.
nodejs-poolController:
- Enable MQTT on dashPanel
- Optional: Enable MQTT on REM (for pressure sensor)
Home Assistant Add-Ons:
- MQTT Broker
- NodeRed
- Visual Studio Code (or other various text editors)
- Optional: HACS
The following sections can be added to the appropriate sections in your HA configuration.yaml file depending on what equipment you have. Pay attention to the rootTopic text for your setup as the default will be different depending on controller setup. In the example below this has been simplified to "pool" for state_topic. The use of an application like MQTT Explorer is valuable for troubleshooting and monitoring messages in real time.
After the configuration file is saved it is nessary to restart HA for new entities to be created or changes to take place.
configuration>server controls>check configuration>restart server
input_number:
pool_tempurature_set_point:
name: Pool Tempurature Set Point
min: 70
max: 90
step: 1
icon: mdi:target
unit_of_measurement: "°F"
pool_chlorine_set_point:
name: Pool Chlorine Set Point
min: 0
max: 100
step: 10
icon: mdi:target
unit_of_measurement: "%"
sensor:
#Pool Controller Sensors
- platform: mqtt
name: Pool Water Temp
state_topic: "pool/state/temps/bodies/1/pool/temp"
unit_of_measurement: '°F'
value_template: "{{ value_json.temp | round(1) }}"
expire_after: 6000
- platform: mqtt
name: Pool Air Temp
state_topic: "pool/state/temps/air"
unit_of_measurement: '°F'
value_template: "{{ value_json.temp | round(1) }}"
expire_after: 6000
- platform: mqtt
name: Pool Pump Flow
icon: mdi:pump
state_topic: "pool/state/pumps/50/v-green165/flow"
value_template: "{{ value_json.flow }}"
- platform: mqtt
name: Pool Heater Status
icon: mdi:fire
state_topic: "pool/state/temps/bodies/1/pool/heatStatus"
value_template: "{{ value_json.heatStatus.desc }}"
- platform: mqtt
name: Pool Chlorinator Status
icon: mdi:check-circle-outline
state_topic: "pool/state/chlorinators/1/aquarite/status"
value_template: "{{ value_json.status.desc }}"
- platform: mqtt
name: Pool Chlorinator Target Output
icon: mdi:chemical-weapon
state_topic: "pool/state/chlorinators/1/aquarite/targetOutput"
value_template: "{{ value_json.targetOutput }}"
unit_of_measurement: '%'
- platform: mqtt
name: Pool Salt Level
icon: mdi:shaker-outline
state_topic: "pool/state/chlorinators/1/aquarite/saltLevel"
value_template: "{{ value_json.saltLevel }}"
unit_of_measurement: ppm
- platform: mqtt
name: Pool PH Level
icon: mdi:beaker-question
state_topic: "pool/state/chemControllers/50/remchem/pHLevel"
value_template: "{{ value_json.pHLevel | round(2) }}"
unit_of_measurement: ' '
expire_after: 6000
- platform: mqtt
name: Pool ORP Level
icon: mdi:beaker-question-outline
state_topic: "pool/state/chemControllers/50/remchem/orpLevel"
value_template: "{{ value_json.orpLevel | round(0) }}"
unit_of_measurement: ' '
expire_after: 6000
- platform: mqtt
name: Pool Saturation Index
icon: mdi:water-check-outline
state_topic: "pool/state/chemControllers/50/remchem/saturationIndex"
value_template: "{{ value_json.saturationIndex | round(2)}}"
unit_of_measurement: ' '
- platform: mqtt
name: Pool Flow Alarm
icon: mdi:pipe
state_topic: "pool/state/chemControllers/50/remchem/alarms/flow"
value_template: "{{ value_json.alarms.flow }}"
- platform: mqtt
name: Pool Filter Pressure
icon: mdi:air-filter
state_topic: "pool/state/pressures/filter"
value_template: "{{ value_json | round(1) }}"
unit_of_measurement: psi
expire_after: 6000
switch:
#Pool Controller Sensors
- platform: mqtt
name: Pool
icon: mdi:pool
state_topic: "pool/state/circuits/6/pool"
value_template: "{{ value_json.isOn }}"
command_topic: "pool/state/circuits/toggleState"
payload_on: '{"id": 6}'
payload_off: '{"id": 6}'
state_on: "on"
state_off: "off"
optimistic: false
retain: false
qos: 0
- platform: mqtt
name: Pool Pump Speed 1
icon: mdi:pump
state_topic: "pool/state/circuits/2/pumpsp1"
value_template: "{{ value_json.isOn }}"
command_topic: "pool/state/circuits/toggleState"
payload_on: '{"id": 2}'
payload_off: '{"id": 2}'
state_on: "on"
state_off: "off"
optimistic: false
retain: false
qos: 0
- platform: mqtt
name: Pool Pump Speed 2
icon: mdi:pump
state_topic: "pool/state/circuits/3/pumpsp2"
value_template: "{{ value_json.isOn }}"
command_topic: "pool/state/circuits/toggleState"
payload_on: '{"id": 3}'
payload_off: '{"id": 3}'
state_on: "on"
state_off: "off"
optimistic: false
retain: false
qos: 0
- platform: mqtt
name: Pool Pump Speed 3
icon: mdi:pump
state_topic: "pool/state/circuits/4/pumpsp3"
value_template: "{{ value_json.isOn }}"
command_topic: "pool/state/circuits/toggleState"
payload_on: '{"id": 4}'
payload_off: '{"id": 4}'
state_on: "on"
state_off: "off"
optimistic: false
retain: false
qos: 0
- platform: mqtt
name: Pool Pump Speed 4
icon: mdi:pump
state_topic: "pool/state/circuits/5/pumpsp4"
value_template: "{{ value_json.isOn }}"
command_topic: "pool/state/circuits/toggleState"
payload_on: '{"id": 5}'
payload_off: '{"id": 5}'
state_on: "on"
state_off: "off"
optimistic: false
retain: false
qos: 0
- platform: mqtt
name: Pool Heater Mode
icon: mdi:fire
state_topic: "pool/state/temps/bodies/1/pool/heatMode"
value_template: "{{ value_json.heatMode.desc }}"
state_on: "Heater"
state_off: "Off"
command_topic: "pool/state/body/heatMode"
payload_on: '{"id":1,"mode":"heater"}'
payload_off: '{"id":1,"mode":"off"}'
optimistic: false
retain: false
qos: 0
climate:
- platform: mqtt
name: "Pool Heater 2"
min_temp: 40
max_temp: 104
modes:
- "off"
- "heat"
current_temperature_topic: "pool/state/temps/bodies/1/pool/temp"
value_template: "{{ value_json.temp }}"
mode_state_topic: "pool/state/temps/bodies/1/pool/heatMode"
mode_state_template: >-
{% if value_json.heatMode.val == 0 %}
off
{% elif value_json.heatMode.val == 1 %}
off
{% elif value_json.heatMode.val == 2 %}
heat
{% endif %}
mode_command_topic: "pool/state/body/heatMode"
mode_command_template: >-
{% set values = { 'heat':'{"heatMode":2, "id":1}', 'off':'{"heatMode":1, "id":1}'} %}
{{ values[value] if value in values.keys() else '{"heatMode":1, "id":1}' }}
action_topic: "pool/state/temps/bodies/1/pool/heatStatus"
action_template: >-
{% if value_json.heatStatus.val == 0 %}
off
{% elif value_json.heatStatus.val == 1 %}
heating
{% endif %}
temperature_command_topic: pool/setpoint #REQUIRES AN AUTOMATION - SEE BELOW
temperature_state_topic: "pool/state/temps/bodies/1/pool/setPoint"
temperature_state_template: "{{ value_json.setPoint }}"
Automation in HA Config for syncing setpoint temperature:
- alias: "pool setpoint converter"
trigger:
platform: mqtt
topic: pool/setpoint
action:
service: mqtt.publish
data_template:
topic: pool/state/body/setPoint # <-- from https://github.com/tagyoureit/nodejs-poolController/wiki/Bindings-Integrations-in-2.0#mqtt
payload: '{"id":1,"setPoint":{{trigger.payload | int}}}' # <-- id sets body/circuit
You will need the following or similar automations to keep the temperature and/or chlorinator set points synchronized between nodejs-poolController and Home Assistant. You will need to remap references to your specific HA and MQTT servers in node-red after importing the code below.
Temperature Set Point
[{"id":"4319aa0f.2cbff4","type":"server-state-changed","z":"f34355e5.bd58d8","name":"Tempurature Set Point","server":"38c4ea68.0b9556","version":3,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"input_number.pool_tempurature_set_point","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":true,"for":0,"forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":180,"y":2160,"wires":[["57f184f1.f9c97c"]]},{"id":"57f184f1.f9c97c","type":"function","z":"f34355e5.bd58d8","name":"Data","func":"msg.payload = {\"id\": 1, \"setPoint\": msg.payload}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":2160,"wires":[["9dfef7f5.e73638"]]},{"id":"9dfef7f5.e73638","type":"mqtt out","z":"f34355e5.bd58d8","name":"","topic":"pool/state/body/setPoint","qos":"0","retain":"","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"f5279b01.b328d8","x":570,"y":2160,"wires":[]},{"id":"846063cc.a4605","type":"mqtt in","z":"f34355e5.bd58d8","name":"","topic":"pool/state/temps/bodies/1/pool/setPoint","qos":"0","datatype":"auto","broker":"f5279b01.b328d8","nl":false,"rap":true,"rh":0,"x":230,"y":2220,"wires":[["3741aa31.3d9186"]]},{"id":"ab1bb7f0.961018","type":"api-call-service","z":"f34355e5.bd58d8","name":"Set Tempurature Target","server":"38c4ea68.0b9556","version":3,"debugenabled":false,"service_domain":"input_number","service":"set_value","entityId":"input_number.pool_tempurature_set_point","data":"{\"value\":\"{{payload}}\"}","dataType":"json","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":890,"y":2220,"wires":[[]]},{"id":"3741aa31.3d9186","type":"json","z":"f34355e5.bd58d8","name":"","property":"payload","action":"","pretty":false,"x":510,"y":2220,"wires":[["ed09e2e2.ba582"]]},{"id":"ed09e2e2.ba582","type":"split","z":"f34355e5.bd58d8","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":670,"y":2220,"wires":[["ab1bb7f0.961018"]]},{"id":"38c4ea68.0b9556","type":"server","name":"Home Assistant","version":1,"legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true},{"id":"f5279b01.b328d8","type":"mqtt-broker","name":"HASSIO - MQTT","broker":"localhost","port":"1883","clientid":"","usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"sessionExpiry":""}]
Chlorinator Set Point
[{"id":"1c3c85e8.30330a","type":"server-state-changed","z":"f34355e5.bd58d8","name":"Chlorine Set Point","server":"38c4ea68.0b9556","version":3,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"input_number.pool_chlorine_set_point","entityidfiltertype":"exact","outputinitially":false,"state_type":"num","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":true,"for":0,"forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":170,"y":2280,"wires":[["670c0c22.2c1e94"]]},{"id":"670c0c22.2c1e94","type":"function","z":"f34355e5.bd58d8","name":"Data","func":"msg.payload = {\"id\": 1, \"poolSetpoint\": msg.payload}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":2280,"wires":[["3e2b068a.f93a8a"]]},{"id":"3e2b068a.f93a8a","type":"mqtt out","z":"f34355e5.bd58d8","name":"","topic":"pool/state/chlorinator","qos":"0","retain":"","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"f5279b01.b328d8","x":560,"y":2280,"wires":[]},{"id":"49f2a840.fdddb8","type":"mqtt in","z":"f34355e5.bd58d8","name":"","topic":"pool/state/chlorinators/1/aquarite/poolSetpoint","qos":"0","datatype":"auto","broker":"f5279b01.b328d8","nl":false,"rap":true,"rh":0,"x":250,"y":2340,"wires":[["dfa3118d.6dceb"]]},{"id":"dda4d920.bb2138","type":"api-call-service","z":"f34355e5.bd58d8","name":"Set Chlorine Target","server":"38c4ea68.0b9556","version":3,"debugenabled":false,"service_domain":"input_number","service":"set_value","entityId":"input_number.pool_chlorine_set_point","data":"{\"value\":\"{{payload}}\"}","dataType":"json","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":870,"y":2340,"wires":[[]]},{"id":"dfa3118d.6dceb","type":"json","z":"f34355e5.bd58d8","name":"","property":"payload","action":"","pretty":false,"x":510,"y":2340,"wires":[["f0cde6ae.d4e118"]]},{"id":"f0cde6ae.d4e118","type":"split","z":"f34355e5.bd58d8","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":670,"y":2340,"wires":[["dda4d920.bb2138"]]},{"id":"38c4ea68.0b9556","type":"server","name":"Home Assistant","version":1,"legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true},{"id":"f5279b01.b328d8","type":"mqtt-broker","name":"HASSIO - MQTT","broker":"localhost","port":"1883","clientid":"","usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"sessionExpiry":""}]
At this point you can make any automation you can dream up. If you need any ideas to start with, here is a list of some of mine.
- Logic to toggle pool "on" state and select pump speeds while keeping them sync'd with nodejs-poolController
- Schedule for the pool pump
- Avoid using electricity during peak hours
- Turn the heat pump on only for days that pool is likely to be used
- Notification if communication drops from the nodejs-poolController (ex: monitor the pressure value for "unavailable", as the MQTT value is setup to expire after 10 minutes)
Of course another way of doing automations in HA is to simply using yaml. The following two automations should keep the chorinator set point synchronized in both directions.
Credits to @truvec
automation:
- id: '808456'
alias: "Set SWG slider"
trigger:
platform: mqtt
topic: "pool/state/chlorinators/1/aquarite/poolSetpoint"
action:
service: input_number.set_value
target:
entity_id: input_number.pool_chlorine_set_point
data:
value: "{{ trigger.payload_json.poolSetpoint }}"
- id: '808457'
alias: "SWG slider moved"
trigger:
platform: state
entity_id: input_number.pool_chlorine_set_point
action:
service: mqtt.publish
data:
topic: "pool/state/chlorinator"
retain: true
payload: "{\"id\":1,\"poolSetpoint\":{{ states('input_number.pool_chlorine_set_point')|round(0)}}}"
Here is a card that I use to display relevant pool information. This will need to be edited for your use case as it contains sensors not created or explained in this writeup. There are also some custom lovelace plugins that I use below that can be installed manually or by using HACS.
- custom:mini-graph-card
- custom:multiple-entity-row
type: vertical-stack
cards:
- type: custom:mini-graph-card
entities:
- entity: sensor.pool_water_temp
name: Pool
- entity: sensor.pool_air_temp
name: Enclosure
- aggregate_func: min
color: gray
entity: binary_sensor.night
show_legend: false
show_line: false
show_points: false
y_axis: secondary
hours_to_show: 24
points_per_hour: 2
name: Pool Tempuratures
show:
labels: true
decimals: 1
state_map:
- label: Night
value: 'off'
- label: Day
value: 'on'
type: ''
- type: entities
title: Pool Control
show_header_toggle: false
entities:
- entity: switch.pool
- entity: input_select.pool_pump_speed
- type: custom:multiple-entity-row
entity: sensor.pool_filter_pressure
name: Pump/Filter
secondary_info: last-changed
show_state: false
entities:
- entity: sensor.pool_filter_pressure
name: Pressure
- entity: sensor.iotawatt_input_9
name: Power
- entity: input_number.pool_tempurature_set_point
- type: custom:multiple-entity-row
entity: sensor.pool_heater_status
name: Pool Heater
secondary_info: last-changed
show_state: false
entities:
- entity: sensor.pool_heater_status
name: Status
- entity: sensor.iotawatt_input_8
name: Power
- entity: switch.pool_heater_mode
name: Enable
toggle: true
- entity: input_number.pool_chlorine_set_point
- type: custom:multiple-entity-row
entity: sensor.pool_salt_level
name: Chlorine
secondary_info: last-changed
show_state: false
entities:
- entity: sensor.pool_salt_level
name: Salt
- entity: sensor.pool_chlorinator_target_output
name: Duty
- entity: input_boolean.make_chlorine
name: Enable
toggle: true
- type: custom:multiple-entity-row
entity: sensor.pool_orp_level
name: Chemical Levels
secondary_info: last-changed
show_state: false
entities:
- entity: sensor.pool_orp_level
name: ORP
- entity: sensor.pool_ph_level
name: PH
- entity: sensor.pool_saturation_index
name: Sat-Index