Progress over the weekend with the ERV DAS
The 999's are me testing the sensor disconnected response.
I have a Pitot tube left over from an RC plane I think I might put it in the inlet air stream
Pin assignment in the Arduino sketch
DHT dht[4] = {DHT(4, DHTTYPE),DHT(0, DHTTYPE),DHT(2, DHTTYPE),DHT(14, DHTTYPE)};
There are 4 DHT22's inside heat exchanger lid, shown below.
Sensor locations
Arduino code
#include <Arduino_JSON.h> #include <ESP8266WiFi.h> #include <MQTT.h> #define LED_PIN LED_BUILTIN //LED_BUILTIN is built in LED #include "DHT.h" // Uncomment whatever type you're using! #define DHTTYPE DHT11 // DHT 11 //#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321 //#define DHTTYPE DHT21 // DHT 21 (AM2301) WiFiClient net; MQTTClient MQTTclient; const char ssid[] = "Network"; const char pass[] = "DF@#$%"; // the IP address for the MQTT server char MQTTip[] = "192.168.1.71"; unsigned long UpdateCount = 12; unsigned long TickCount = UpdateCount-1; unsigned long PacketCount = 0; unsigned long lastMillis = 0; DHT dht[4] = {DHT(4, DHTTYPE),DHT(0, DHTTYPE),DHT(2, DHTTYPE),DHT(14, DHTTYPE)}; DHT loft(12, DHT11); void setup() { pinMode(LED_PIN, OUTPUT); Serial.begin(115200); WiFi.begin(ssid, pass); // Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino. // You need to set the IP address directly. MQTTclient.begin(MQTTip, net); MQTTclient.onMessage(messageReceived); WiFiconnect(); MQTTclient.publish("/ervdas/status", "start"); for(int i = 0;i < 4;i++) { dht[i].begin(); } loft.begin(); MQTTclient.publish("/ervdas/status", "run"); } void loop() { MQTTclient.loop(); delay(10); // <- fixes some issues with WiFi stability if (!MQTTclient.connected()) { WiFiconnect(); } // publish a message roughly every second. if (millis() - lastMillis > (UpdateCount * 1000)) { lastMillis = millis(); SendMQTT(); } delay(100); } void WiFiconnect() { Serial.print("checking wifi..."); Serial.println(ssid); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); digitalWrite(LED_PIN, LOW); delay(500); digitalWrite(LED_PIN, HIGH); } Serial.println("\nWiFi Connected! "); Serial.println( WiFi.localIP()); Serial.print("\nMQTT connecting..."); while (!MQTTclient.connect(WiFi.localIP().toString().c_str() , "try", "try")) { Serial.print("."); delay(800); digitalWrite(LED_PIN, LOW); delay(200); digitalWrite(LED_PIN, HIGH); } Serial.println("\nMQTT Connected!"); digitalWrite(LED_PIN, LOW); MQTTclient.subscribe("/ervdas/control"); MQTTclient.publish("/ervdas/status", "start"); MQTTclient.publish("/ervdas/localip", "/ervdas/localip/" + WiFi.localIP().toString()); } void SendMQTT() { digitalWrite(LED_PIN, LOW); JSONVar myArray; //STALE myArray[0] = (!isnan(dht[0].readTemperature()) ? dht[0].readTemperature() : 999); myArray[1] = (!isnan(dht[0].readHumidity()) ? dht[0].readHumidity() : 999); //FRESH myArray[2] = (!isnan(dht[1].readTemperature()) ? dht[1].readTemperature() : 999); myArray[3] = (!isnan(dht[1].readHumidity()) ? dht[1].readHumidity() : 999); //INLET myArray[4] = (!isnan(dht[2].readTemperature()) ? dht[2].readTemperature() : 999); myArray[5] = (!isnan(dht[2].readHumidity()) ? dht[2].readHumidity() : 999); //EXHAUST myArray[6] = (!isnan(dht[3].readTemperature()) ? dht[3].readTemperature() : 999); myArray[7] = (!isnan(dht[3].readHumidity()) ? dht[3].readHumidity() : 999); //LOFT myArray[8] = (!isnan(loft.readTemperature()) ? loft.readTemperature() : 999); myArray[9] = (!isnan(loft.readHumidity()) ? loft.readHumidity() : 999); //MISC myArray[10] = (PacketCount++); myArray[11] = WiFi.RSSI(); myArray[12] = analogRead(0); String jsonString = JSON.stringify(myArray); MQTTclient.publish("/ervdas/sensors", jsonString); Serial.print("/ervdas/sensors " ); Serial.print(jsonString ); Serial.println(); digitalWrite(LED_PIN, HIGH); } float toFixed(float f, int dp) { char buf[40] = {0, }; sprintf(buf, "%03d", f); return atof(buf); } void messageReceived(String &topic, String &payload) { digitalWrite(LED_PIN, LOW); Serial.println("incoming: " + topic + " - " + payload); if(topic == "/ervdas/control") { if(payload.startsWith("UpdateCount")) { UpdateCount = (long)payload.substring(12).toInt(); TickCount = UpdateCount -1; } else if(payload.startsWith("read")) { SendMQTT(); MQTTclient.publish("/ervdas/localip", "/ervdas/localip/" + WiFi.localIP().toString()); } MQTTclient.publish("/ervdas/payload", topic + "/" + payload); } digitalWrite(LED_PIN, HIGH); }
Device driver
metadata { definition(name: "Greenway MQTT ERV DAS Driver", namespace: "Greenway", author: "Nick Goodey") { capability "Initialize" capability "Sensor" capability "Polling" capability "Battery" //ERV DAS attribute "StaleTile", "String" attribute "StaleTemp", "Number" attribute "StaleHumidity", "Number" attribute "FreshTile", "String" attribute "FreshTemp", "Number" attribute "FreshHumidity", "Number" attribute "InletTile", "String" attribute "InletTemp", "Number" attribute "InletHumidity", "Number" attribute "ExhaustTile", "String" attribute "ExhaustTemp", "Number" attribute "ExhaustHumidity", "Number" attribute "LoftTile", "String" attribute "LoftTemp", "Number" attribute "LoftHumidity", "Number" attribute "Packet", "Number" attribute "RSSI", "Number" attribute "Analog", "Number" attribute "ExhaustStaleTile", "String" attribute "ExhaustStaleTemp", "Number" attribute "ExhaustStaleHumidity", "Number" attribute "FreshInletTile", "String" attribute "FreshInletTemp", "Number" attribute "FreshInletHumidity", "Number" } preferences { input name: "MQTTBroker", type: "text", title: "MQTT Broker Address:", required: true, displayDuringSetup: true input name: "username", type: "text", title: "MQTT Username:", description: "(blank if none)", required: false, displayDuringSetup: true input name: "password", type: "password", title: "MQTT Password:", description: "(blank if none)", required: false, displayDuringSetup: true input name: "topicSub", type: "text", title: "Topic to Subscribe:", description: "Example Topic (topic/device/#)", required: false, displayDuringSetup: true input name: "topicCon", type: "text", title: "Topic to control:", description: "Example Topic (topic/device/#)", required: false, displayDuringSetup: true input name: "topicPoll", type: "text", title: "Topic to poll device:", description: "Example Topic (topic/device/#)", required: false, displayDuringSetup: true input("logEnable", "bool", title: "Enable logging", required: true, defaultValue: true) } } def installed() { log.info "installed..." } def poll() { displayDebugLog("poll") try { topic = settings?.topicPoll if (logEnable) log.debug "Poll: $topic/read" interfaces.mqtt.publish(topic, "read", 1, false) } catch (e) { log.error "Device Poll error: ${e.message}" } } // Parse incoming device messages to generate events def parse(String description) { try { displayDebugLog("Parse") displayDebugLog(description); displayDebugLog(did); did = device.getId() state.DeviceID = did // parse message mqtt = interfaces.mqtt.parseMessage(description) if (logEnable) log.debug mqtt.topic if (logEnable) log.debug mqtt.payload state.topic = mqtt.topic json = new groovy.json.JsonSlurper().parseText(mqtt.payload) /* //STALE myArray[0] = dht[0].readTemperature(); myArray[1] = dht[0].readHumidity(); //FRESH myArray[2] = dht[1].readTemperature(); myArray[3] = dht[1].readHumidity(); //INLET myArray[4] = dht[2].readTemperature(); myArray[5] = dht[2].readHumidity(); //EXHAUST myArray[6] = dht[3].readTemperature(); myArray[7] = dht[3].readHumidity(); //LOFT myArray[8] = loft.readTemperature(); myArray[9] = loft.readHumidity(); //MISC myArray[9] = (PacketCount++); myArray[10] = WiFi.RSSI(); myArray[11] = analogRead(0); */ //Double.parseDouble( state.StaleTemp = (float)(json[0] * 100)/100.0 state.StaleHumidity = (float)(json[1] * 100)/100.0 sendEvent(name: "StaleTemp", value: state.StaleTemp) sendEvent(name: "StaleHumidity", value: state.StaleHumidity) sendEvent(name: "StaleTile", value: "Stale Air<br>$state.StaleTemp °C<BR>$state.StaleHumidity %") state.FreshTemp = (float)(json[2] * 100)/100.0 state.FreshHumidity = (float)(json[3] * 100)/100.0 sendEvent(name: "FreshTemp", value: state.FreshTemp) sendEvent(name: "FreshHumidity", value: state.FreshHumidity) sendEvent(name: "FreshTile", value: "Fresh Air<br>$state.FreshTemp °C<BR>$state.FreshHumidity %") state.InletTemp = (float)(json[4] * 100)/100.0 state.InletHumidity = (float)(json[5] * 100)/100.0 sendEvent(name: "InletTemp", value: state.InletTemp) sendEvent(name: "InletHumidity", value: state.InletHumidity) sendEvent(name: "InletTile", value: "Intake Air<br>$state.InletTemp °C<BR>$state.InletHumidity %") state.ExhaustTemp = (float)(json[6] * 100)/100.0 state.ExhaustHumidity = (float)(json[7] * 100)/100.0 sendEvent(name: "ExhaustTemp", value: state.ExhaustTemp) sendEvent(name: "ExhaustHumidity", value: state.ExhaustHumidity) sendEvent(name: "ExhaustTile", value: "Exhaust Air<br>$state.ExhaustTemp °C<BR>$state.ExhaustHumidity %") state.LoftTemp = (float)(json[8] * 100)/100.0 state.LoftHumidity = (float)(json[9] * 100)/100.0 sendEvent(name: "LoftTemp", value: state.ExhaustTemp) sendEvent(name: "LoftHumidity", value: state.ExhaustHumidity) sendEvent(name: "LoftTile", value: "Loft Air<br>$state.LoftTemp °C<BR>$state.LoftHumidity %") sendEvent(name: "Packet", value: json[10]) sendEvent(name: "RSSI", value: json[11]) sendEvent(name: "Analog", value: json[12]) state.ExhaustStaleTemp = (float)( (state.StaleTemp - state.ExhaustTemp) * 1000)/1000.0 state.ExhaustStaleHumidity = (float)( (state.StaleHumidity - state.ExhaustHumidity) * 100)/100.0 sendEvent(name: "ExhaustStaleTemp", value: state.ExhaustStaleTemp) sendEvent(name: "ExhaustStaleHumidity", value: state.ExhaustStaleHumidity) sendEvent(name: "ExhaustStaleTile", value: "Exhaust - Stale Air<br>$state.ExhaustStaleTemp °C<BR>$state.ExhaustStaleHumidity %") state.FreshInletTemp = (float)( (state.FreshTemp - state.InletTemp) * 1000)/1000.0 state.FreshInletHumidity = (float)( (state.StaleHumidity - state.ExhaustHumidity) * 100)/100.0 sendEvent(name: "FreshInletTemp", value: state.FreshInletTemp) sendEvent(name: "FreshInletHumidity", value: state.FreshInletHumidity) sendEvent(name: "FreshInletTile", value: "Fresh - Inlet Air<br>$state.FreshInletTemp °C<BR>$state.FreshInletHumidity %") } catch (Exception e) { log.error "Parse error: ${e.message}" } } def updated() { if (logEnable) log.info "Updated..." initialize() } def uninstalled() { if (logEnable) log.info "Disconnecting from mqtt" interfaces.mqtt.disconnect() } def initialize() { displayDebugLog("initialize") if (logEnable) runIn(900, logsOff) state.ThisCharge = 0 state.ChargeLimit = 0 state.Relay = -1 MQTTconnect() unschedule() schedule("0/10 * * * * ? *", MQTTconnect) } def MQTTconnect() { try { def mqttInt = interfaces.mqtt if (mqttInt.isConnected()) { displayDebugLog( "Allready Connected to: $MQTTBroker $topicSub") return } def clientID = "hubitat-" + device.deviceNetworkId state.clientID = clientID displayDebugLog( "Allready Connected to: $MQTTBroker $settings?.MQTTBroker/$settings?.topicSub") //open connection mqttbroker = "tcp://" + settings?.MQTTBroker + ":1883" mqttInt.connect(mqttbroker, clientID, settings?.username, settings?.password) //give it a chance to start pauseExecution(500) mqttInt.subscribe(settings?.topicSub) log.info "Connection established: $MQTTBroker $topicSub" log.info "clientID: $clientID" log.info "Subscribed to: $topicSub" } catch (e) { log.error "MQTTconnect error: ${e.message}" } } def mqttClientStatus(String status) { log.error "MQTTStatus- error: ${status}" } def logsOff() { log.warn "Debug logging disabled." device.updateSetting("logEnable", [value: "false", type: "bool"]) } private def displayDebugLog(message) { if (logEnable) log.debug "${device.displayName}: ${message}" } private def displayInfoLog(message) { log.info "${device.displayName}: ${message}" }
Not sure who I cribbed the above off originally I think it was a community driver