{"id":1764,"date":"2019-11-16T20:07:43","date_gmt":"2019-11-17T04:07:43","guid":{"rendered":"https:\/\/partofthething.com\/thoughts\/?p=1764"},"modified":"2020-04-16T22:05:02","modified_gmt":"2020-04-17T05:05:02","slug":"adding-temperature-sensors-to-a-hot-water-heater","status":"publish","type":"post","link":"https:\/\/partofthething.com\/thoughts\/adding-temperature-sensors-to-a-hot-water-heater\/","title":{"rendered":"Adding temperature sensors to a hot water heater"},"content":{"rendered":"\n<div class=\"wp-block-image\"><figure class=\"alignright size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/bad-ignitor_crop-725x1024.jpg\" alt=\"A igniter with a layer of white oxide powder all over it. \" class=\"wp-image-1767\" width=\"224\" height=\"316\" srcset=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/bad-ignitor_crop-725x1024.jpg 725w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/bad-ignitor_crop-212x300.jpg 212w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/bad-ignitor_crop-768x1085.jpg 768w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/bad-ignitor_crop-1087x1536.jpg 1087w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/bad-ignitor_crop.jpg 1449w\" sizes=\"auto, (max-width: 224px) 100vw, 224px\" \/><figcaption>The bad igniter<\/figcaption><\/figure><\/div>\n\n\n\n<p>I&#8217;ve got one of those hydronic home heating systems where hot water from the hot water heater gets pumped to radiators around the house in addition to heating up water for faucets. A few days ago it died on me and threw an error code indicating something was wrong with ignition. I took a look at the igniter and found that it was full of an oxide layer. <\/p>\n\n\n\n<p>After sandpapering it, it worked great, but I ordered a spare for when this inevitably happens again. Along the way, it occurred to me that it&#8217;d be kind of fun to have instrumentation on my hot water heater. I just got it up and running. <\/p>\n\n\n\n<p>Way back in my first post about <a href=\"https:\/\/partofthething.com\/thoughts\/hot-tub-controller\/\">hot tubs<\/a>, I used OneWire sensors called <a href=\"https:\/\/datasheets.maximintegrated.com\/en\/ds\/DS18B20.pdf\">Dallas 18B20s (datasheet)<\/a> with an Arduino 2009. They worked great at hot water temperature, so I decided to try them out again. This time, rather than using an Arduino, I&#8217;m using a ESP8266 microcontroller. These are cheap and have Wi-Fi, so I can easily get the data into my <a href=\"https:\/\/partofthething.com\/thoughts\/home-automation-with-z-wave-home-assistant-aeon-multisensor-hue-lights-and-a-raspberry-pi-2\/\">home assistant setup<\/a>, just like I did with <a href=\"https:\/\/partofthething.com\/thoughts\/enlighten-your-old-furnace-with-a-raspberry-pi-home-assistant-an-esp8266-and-some-relays\/\">my mom&#8217;s furnace<\/a>, my <a href=\"https:\/\/partofthething.com\/thoughts\/making-my-analog-doorbell-smart-by-simply-attaching-a-7-sensor-to-it\/\">doorbell<\/a>, and other stuff. <\/p>\n\n\n\n<p>Step one is to solder a bunch of sensors together. I wanted to get readings on all the different pipes going into and out of my hot water heater. I went down there and measured how much space I&#8217;d need between each sensor. Then I soldered them up. Notably 18B20s can work in &#8220;parasite mode&#8221; with just two wires, but t<a href=\"https:\/\/github.com\/PaulStoffregen\/OneWire\/issues\/58\">here are problems with parasite mode on ESP8266&#8217;s<\/a>, and in prototype testing I was unable to get that mode to work. So I just wired them up to 3 wires. <a href=\"https:\/\/randomnerdtutorials.com\/esp8266-ds18b20-temperature-sensor-web-server-with-arduino-ide\/\">This tutorial<\/a> is a good one for wiring up these sensors.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"682\" src=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2553-1024x682.jpg\" alt=\"A sensor with three wires soldered to it. \" class=\"wp-image-1768\" srcset=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2553-1024x682.jpg 1024w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2553-300x200.jpg 300w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2553-768x512.jpg 768w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2553-1536x1024.jpg 1536w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2553.jpg 2000w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>One Dallas18B20 soldered into my wire-o-sensors. Black goes to GND on the ESP, red goes to +5V on the ESP, and clear goes to GPIO 2, which is also jumpered to +5V with a 4.7 kOhm resistor<\/figcaption><\/figure>\n\n\n\n<!--more-->\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"682\" src=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2548-1024x682.jpg\" alt=\"The whole wire with 5 sensors and the microcontroller layed out on a desk\" class=\"wp-image-1769\" srcset=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2548-1024x682.jpg 1024w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2548-300x200.jpg 300w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2548-768x512.jpg 768w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2548-1536x1024.jpg 1536w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2548.jpg 2000w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>All 5 of the sensors are wired identically and soldered together into the ESP8266 microcontroller. I need a good name for this because it could totally be productized!<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"683\" src=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2554-1024x683.jpg\" alt=\"The ESP8266 microcontroller with soldered wires\" class=\"wp-image-1770\" srcset=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2554-1024x683.jpg 1024w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2554-300x200.jpg 300w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2554-768x512.jpg 768w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2554-1536x1024.jpg 1536w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2554.jpg 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>I am not proud of this particular solder job connecting the wire to the ESP8266.<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"682\" src=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2557-1024x682.jpg\" alt=\"A sensor zip-tied to a pipe\" class=\"wp-image-1771\" srcset=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2557-1024x682.jpg 1024w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2557-300x200.jpg 300w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2557-768x512.jpg 768w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2557-1536x1024.jpg 1536w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2557.jpg 2000w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>One of the sensors zip-tied to the hot water heater pipe. Since it&#8217;s not great thermal contact, we can expect measured temperatures to be biased low.<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"682\" src=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2560.jpg-1024x682.png\" alt=\"Full water heater with labels to all sensors\" class=\"wp-image-1772\" srcset=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2560.jpg-1024x682.png 1024w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2560.jpg-300x200.png 300w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2560.jpg-768x512.png 768w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_2560.jpg.png 1333w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>The whole installed system<\/figcaption><\/figure>\n\n\n\n<p>For software, I already have a MQTT server up and running from my home automation setups, so the easiest thing is to just transmit the data via Wi-Fi\/MQTT to my server and then receive\/process it with Home Assistant. <\/p>\n\n\n\n<p>The ESP8266 code is pretty straightforward. It connects to Wi-Fi and MQTT and then just sits around for a pre-determine delay (60 seconds) after which it reads the sensors and transmits them. Here it is:<\/p>\n\n\n\n<div class=\"wp-block-group\"><div class=\"wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow\">\n<pre class=\"wp-block-code\"><code>\/*\nHot water heater temperature monitoring station.\n\nThis reads a few temperature sensors at various points\non a hot water heater (or whatever) and transmits\nthem back to some place where they can be read and \nprocessed (like a Home Assistant system).\n\nTemperature sensors used here are DS18B20's in non-parasite mode.\nThese have good temperature resolution up to hot water temperatures.\n*\/\n\n#include &lt;OneWire.h>\n#include &lt;DallasTemperature.h>\n\n#include &lt;ESP8266WiFi.h>\n#include &lt;ESP8266mDNS.h>\n#include &lt;PubSubClient.h>\n\n#define wifi_ssid \"Wifi SSID\"\n#define wifi_password \"Actual password\"\n\n#define mqtt_server \"dummy-mqtt-server.com\"\n#define mqtt_will_topic \"home\/status\/garage\"\n#define mqtt_user \"user\"\n#define mqtt_password \"password\"\n\n#define ONE_WIRE_BUS D2\n\nOneWire oneWire(ONE_WIRE_BUS);\nDallasTemperature sensors(&amp;oneWire);\nWiFiClientSecure  espClient;\nPubSubClient client(espClient);\n\nint numDevices;\nString baseTopic = \"home\/garage\/\";\nunsigned long previousMillis = 0;\nconst long intervalMillis = 60000; \/\/ how often to update \n\nDeviceAddress tempDeviceAddress; \n\nvoid setup(){\n  pinMode(D2, INPUT);\n  pinMode(D2, OUTPUT);\n  sensors.begin();\n  Serial.begin(9600);\n  Serial.print(\"Greetings from the water heater.\");\n  setup_wifi();\n  setup_mqtt();\n\n  Serial.print(\"Initializing devices...\");\n  numDevices= sensors.getDeviceCount();\n  Serial.print(\"Found \");\n  Serial.print(numDevices, DEC);\n  Serial.println(\" devices.\");\n\n  for(int i=0;i&lt;numDevices; i++){\n    if(sensors.getAddress(tempDeviceAddress, i)){\n      Serial.print(\"Found device \");\n      Serial.print(i, DEC);\n      Serial.print(\" @: \");\n      printAddress(tempDeviceAddress);\n      Serial.println();\n    } else {\n      Serial.print(\"Found phantom device at \");\n      Serial.print(i, DEC);\n      Serial.print(\" but could not detect address. Check power and cabling\");\n    }\n  }\n}\n\nvoid loop(){ \n  unsigned long currentMillis = millis();\n\n  if (!client.connected()) {\n      reconnect();\n  }\n  client.loop();\n  ArduinoOTA.handle();\n\n  if (currentMillis - previousMillis >= intervalMillis) {\n    previousMillis = currentMillis;\n    readSensors();\n  }\n\n}\n\nvoid readSensors() {\n  String fullTopic;\n  String value;\n  String address;\n\n  sensors.requestTemperatures();\n\n  for(int i=0;i&lt;numDevices; i++){\n    if(sensors.getAddress(tempDeviceAddress, i)){\n      address = (char *) tempDeviceAddress;\n      Serial.print(\"Temperature @: \");\n      Serial.print(i,DEC);\n      float tempC = sensors.getTempC(tempDeviceAddress);\n      printAddress(tempDeviceAddress);\n      Serial.print(\" \u00b0C: \");\n      Serial.println(tempC);\n      fullTopic = baseTopic + i;\n      value = String(tempC);\n      client.publish(fullTopic.c_str(), value.c_str(), true);\n    }\n  }\n}\n\nvoid printAddress(DeviceAddress deviceAddress) {\n  for (uint8_t i = 0; i &lt; 8; i++){\n    if (deviceAddress&#91;i] &lt; 16) Serial.print(\"0\");\n      Serial.print(deviceAddress&#91;i], HEX);\n  }\n}\n\nvoid setup_wifi() {\n  espClient.setInsecure();  \/\/ required since bearssl\n  delay(10);\n  Serial.println();\n  Serial.print(\"Connecting to \");\n  Serial.println(wifi_ssid);\n  WiFi.mode(WIFI_STA);\n  WiFi.begin(wifi_ssid, wifi_password);\n  while (WiFi.status() != WL_CONNECTED) {\n    delay(500);\n    Serial.print(\".\");\n  }\n  Serial.println(\"\");\n  Serial.println(\"WiFi connected\");\n}\n\nvoid setup_mqtt() {\n    client.setServer(mqtt_server, 8883);\n    client.publish(mqtt_will_topic, \"1\", true);\n}\n\nvoid reconnect() {\n  int retryCount=0;\n  while (!client.connected()) {\n    Serial.print(\"Attempting MQTT connection...\");\n    if (client.connect(\"Garage\", mqtt_user, mqtt_password, mqtt_will_topic, \n                        1, 1, \"0\")) {\n      Serial.println(\"connected\");\n      client.publish(mqtt_will_topic, \"1\", true);\n      \n    } else {\n      Serial.print(\"failed, rc=\");\n      Serial.print(client.state());\n      Serial.println(\" try again in 3 seconds\");\n      delay(3000);\n      retryCount++;\n      if (retryCount>20) {\n        Serial.println(\"Goofed up. Restarting.\");\n        ESP.restart();\n      }\n    }\n  }\n  Serial.print(\"MQTT connected.\");\n}\n<\/code><\/pre>\n<\/div><\/div>\n\n\n\n<p>Then the setup in Home Assistant configuration is just a few <a href=\"https:\/\/www.home-assistant.io\/integrations\/sensor.mqtt\/\">MQTT sensors<\/a>. To figure out which sensor was which I had to put my finger on them individually to see which one heated up first.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Hot water heater sensor order from esp is 3 2 1 0 4\n  - platform: mqtt\n    name: Heat outlet\n    state_topic: \"home\/garage\/3\"\n    device_class: temperature\n    unit_of_measurement: '\u00b0C'\n  - platform: mqtt\n    name: Heat inlet\n    state_topic: \"home\/garage\/2\"\n    device_class: temperature\n    unit_of_measurement: '\u00b0C'\n  - platform: mqtt\n    name: Faucet inlet\n    state_topic: \"home\/garage\/1\"\n    device_class: temperature\n    unit_of_measurement: '\u00b0C'\n  - platform: mqtt\n    name: Faucet outlet\n    state_topic: \"home\/garage\/0\"\n    device_class: temperature\n    unit_of_measurement: '\u00b0C'\n  - platform: mqtt\n    name: Garage ambient\n    state_topic: \"home\/garage\/4\"\n    device_class: temperature\n    unit_of_measurement: '\u00b0C'\n<\/code><\/pre>\n\n\n\n<p>With that configured, I went to the front end and added a new History Graph card from Lovelace and choose the new sensors by name. An hour later, the data looked like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"910\" height=\"674\" src=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/hot-water-heater-graphs.png\" alt=\"Graphs of temperatures vs. time\" class=\"wp-image-1773\" srcset=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/hot-water-heater-graphs.png 910w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/hot-water-heater-graphs-300x222.png 300w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/hot-water-heater-graphs-768x569.png 768w\" sizes=\"auto, (max-width: 910px) 100vw, 910px\" \/><figcaption>Temperature data from the hot water heater sensor line. I turned off the circulation pump around 6:54 P.M. and you can nicely see the heating loop converge to a lower temperature. Beautiful!<\/figcaption><\/figure>\n\n\n\n<p>I love it. And of course, I added an e-mail alert when the faucet outlet temperature drops below 30 \u00b0C so I&#8217;ll be able to swap out the igniters before the thing cools all the way down. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve got one of those hydronic home heating systems where hot water from the hot water heater gets pumped to radiators around the house in addition to heating up water for faucets. A few days ago it died on me and threw an error code indicating something was wrong with ignition. I took a look &hellip; <a href=\"https:\/\/partofthething.com\/thoughts\/adding-temperature-sensors-to-a-hot-water-heater\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Adding temperature sensors to a hot water heater<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":1765,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":4,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":""},"categories":[75],"tags":[],"class_list":["post-1764","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-home-automation"],"_links":{"self":[{"href":"https:\/\/partofthething.com\/thoughts\/wp-json\/wp\/v2\/posts\/1764","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/partofthething.com\/thoughts\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/partofthething.com\/thoughts\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/partofthething.com\/thoughts\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/partofthething.com\/thoughts\/wp-json\/wp\/v2\/comments?post=1764"}],"version-history":[{"count":4,"href":"https:\/\/partofthething.com\/thoughts\/wp-json\/wp\/v2\/posts\/1764\/revisions"}],"predecessor-version":[{"id":1836,"href":"https:\/\/partofthething.com\/thoughts\/wp-json\/wp\/v2\/posts\/1764\/revisions\/1836"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/partofthething.com\/thoughts\/wp-json\/wp\/v2\/media\/1765"}],"wp:attachment":[{"href":"https:\/\/partofthething.com\/thoughts\/wp-json\/wp\/v2\/media?parent=1764"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/partofthething.com\/thoughts\/wp-json\/wp\/v2\/categories?post=1764"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/partofthething.com\/thoughts\/wp-json\/wp\/v2\/tags?post=1764"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}