Z-UNO Pool Temperature Monitor

I wasn’t able to find a device that met all of my needs for a Smart Things compatible pool temperature so I built one using a Z-UNO and a custom device handler. It uses a Z-UNO, a DS18B20 Sensor and that’s about it hardware wise. I did 3D print a custom water proof enclosure but that isn’t necessary for it work. I also used heat shrink tubing around the sensor so that the chemicals inside of my pool wouldn’t corrode the sensor over time.

Arduino Code
#include <ZUNO_DS18B20.h>
// Define pin DS18B20 is connected to.
#define PIN_DS18B20 11
OneWire ow(PIN_DS18B20);
// Connect to OneWire temperature sensor.
DS18B20Sensor ds1820(&ow);
byte addr1[8];
// Temperature reading storage.
int temp;
ZUNO_SETUP_CHANNELS( ZUNO_SENSOR_MULTILEVEL(ZUNO_SENSOR_MULTILEVEL_TYPE_TEMPERATURE, 0, SENSOR_MULTILEVEL_SIZE_ONE_BYTE, SENSOR_MULTILEVEL_PRECISION_ZERO_DECIMALS, getterTemp) );
void setup() { pinMode(LED_BUILTIN, OUTPUT); }
void loop() {
ds1820.scanAloneSensor(addr1);
// Turn on status light.
digitalWrite(LED_BUILTIN, HIGH);
// Pull temperature from 18B20 sensors.
float temerature = ds1820.getTemperature(addr1);
// Set temperature in fahrenheit
temp = int(temerature*180+3200);
// Send data to hub
zunoSendReport(1);
// Turn off status light.
digitalWrite(LED_BUILTIN, LOW);
// Send every 30 seconds
delay(30000);
}
word getterTemp() {
return temp;
}

Device Handler
metadata {
definition (name: “Pool Temp”, author: “Buddy Edwards”) {
capability “Temperature Measurement”
}

    simulator {
            status "temperature report 70°F": zwave.sensorMultilevelV2.sensorMultilevelReport(scaledSensorValue: 70.0, precision: 1, sensorType: 1, scale: 1).incomingMessage()
    }

    tiles {
            standardTile("refresh", "command.refresh", inactiveLabel: false,
                         decoration: "flat") {
                    state "default", label:'', action:"refresh.refresh",
                          icon:"st.secondary.refresh"
            }

            valueTile("temperature", "device.temperature", width: 3, height: 2,
                        canChangeIcon: true, inactiveLabel: true ) {
                    state("temperature", label:'${currentValue}°',
                            backgroundColors:[
                                    [value: 84, color: "#00ace6"],
                                    [value: 91, color: "#ff9900"],
                                    [value: 96, color: "#db3d3d"]
                            ]
                    )
            }

            main (["temperature"])
            details (["temperature"])
    }

}

def parse(String description) {
def result = null
def cmd = zwave.parse(description, [0x60: 3])
if (cmd) {
result = zwaveEvent(cmd)
log.debug “Parsed {cmd} to {result.inspect()}”
} else {
log.debug “Non-parsed event: ${description}”
}
result
}

// def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv1.SensorBinaryReport cmd)
//{
// // Version 1 of SensorBinary doesn’t have a sensor type
// createEvent(name:“sensor”, value: cmd.sensorValue ? “active” : “inactive”)
//}

def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd)
{
def map = [ displayed: true, value: cmd.scaledSensorValue.toString() ]
switch (cmd.sensorType) {
case 1:
map.name = “temperature”
map.unit = cmd.scale == 0 ? “F” : “C”
break;
}
createEvent(map)
}

// def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd)
//{
// createEvent(name:“sensor”, value: cmd.value ? “active” : “inactive”)
//}

def zwaveEvent(physicalgraph.zwave.commands.associationv2.AssociationReport cmd) {
def result =
if (cmd.nodeId.any { it == zwaveHubNodeId }) {
result << createEvent(descriptionText: “device.displayName is associated in group {cmd.groupingIdentifier}”)
} else if (cmd.groupingIdentifier == 1) {
// We’re not associated properly to group 1, set association
result << createEvent(descriptionText: “Associating device.displayName in group {cmd.groupingIdentifier}”)
result << response(zwave.associationV1.associationSet(groupingIdentifier:cmd.groupingIdentifier, nodeId:zwaveHubNodeId))
}
result
}

def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x98: 1, 0x20: 1])

    // can specify command class versions here like in zwave.parse
    if (encapsulatedCommand) {
            return zwaveEvent(encapsulatedCommand)
    }

}

def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x30: 1, 0x31: 1])

    // can specify command class versions here like in zwave.parse
    log.debug ("Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}")

    if (encapsulatedCommand) {
            return zwaveEvent(encapsulatedCommand)
    }

}

def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiInstanceCmdEncap cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x30: 1, 0x31: 1])

    // can specify command class versions here like in zwave.parse
    log.debug ("Command from instance ${cmd.instance}: ${encapsulatedCommand}")

    if (encapsulatedCommand) {
            return zwaveEvent(encapsulatedCommand)
    }

}

def zwaveEvent(physicalgraph.zwave.Command cmd) {
createEvent(descriptionText: “{device.displayName}: {cmd}”)
}

def refresh() {
delayBetween([
zwave.sensorMultilevelV2.sensorMultilevelGet(sensorType:1, scale:1).format() // get temp in Fahrenheit
], 1200)
}

def poll() {
zwave.sensorMultilevelV2.sensorMultilevelGet(sensorType:1, scale:1).format()
}

//def configure() {
// delayBetween([
// zwave.configurationV1.configurationSet(parameterNumber:1, size:2, scaledConfigurationValue:100).format(),
// ])
//}

I figure this may help someone out as a starting point for their own pool temp monitor.

1 Like

Thank you for this! I am using your idea to build out my own temperature sensor - the main difference being I want to add a total of 3 sensors:

  • 1 x DS18B20 for pool
  • 1 x DS18B20 for spa
  • 1 x DHT11 for ambient temperature and humidity

This will allow me to have an all-encompassing temperature & humidity sensor for my backyard. I plan to use a Z-uno Shield to make it waterproof, and since I do not have access to a power outlet, it will be powered by a battery. I will post pictures as I progress.

In the meantime, anything I should watch out for, or anything you would recommend now that you have gone through the whole process? How has it held up so far for you?