#include #include #include enum { SECOND = 1000, PERIOD = 30*SECOND, }; enum pins { SOLENOID_PIN = 21 }; enum tunings { P = 2, I = 5, D = 1, }; enum { SOLENOID_WINDOW = 5000 }; const char ssid[] = "Pixel_6504"; const char password[] = "zj3av9sjev7ed8j"; const char humidityUrl[] = "http://hvac.samanthony.xyz/humidity"; const char targetUrl[] = "http://hvac.samanthony.xyz/target_humidity"; double pidInput, pidOutput, pidSetpoint; PID pid(&pidInput, &pidOutput, &pidSetpoint, P, I, D, DIRECT); void setup(void) { pinMode(SOLENOID_PIN, OUTPUT); Serial.begin(9600); while (!Serial) {} pid.SetOutputLimits(0, SOLENOID_WINDOW); pid.SetMode(AUTOMATIC); WiFi.begin(ssid, password); Serial.print("Connecting to WiFi..."); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); } Serial.println(" connected."); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } void loop(void) { static unsigned long lastUpdate = 0; // Last time humidity and target were retrived from server. static float humidity = 0.0; // Measured humidity of the building. static float target = 0.0; // Target humidity. unsigned long now = millis(); if (now - lastUpdate > PERIOD) { // Retrieve measured and target humidity from the server. if (get(humidityUrl, &humidity) != 0 || get(targetUrl, &target) != 0) Serial.println("Failed to get humidity from server."); lastUpdate = now; Serial.printf("Measured humidity: %.2f%%\n", humidity); Serial.printf("Target humidity: %.2f%%\n", target); } pidInput = humidity; pidSetpoint = target; pid.Compute(); writeSolenoidPin(pidOutput); } // Make a GET request to the server and set *x to the float value that it responds with. // Return non-zero on error. int get(const char *url, float *x) { if (WiFi.status() != WL_CONNECTED) { Serial.println("WiFi not connected."); return 1; } // Send request to server. HTTPClient http; Serial.printf("GET %s\n", url); http.begin(url); int responseCode = http.GET(); Serial.printf("HTTP response code: %d\n", responseCode); if (responseCode != HTTP_CODE_OK) { http.end(); return 1; } // Parse response. int status = parseFloat(http.getString().c_str(), x); http.end(); // Cannot be freed before parseHumidity() because response is stored in the http buffer. return status; } // Parse the value of str into *x. Returns non-zero on error. int parseFloat(const char *str, float *x) { if (sscanf(str, "%f", x) != 1) { Serial.printf("Failed to parse float: '%s'\n", str); return 1; } return 0; } void writeSolenoidPin(double pidOutput) { static unsigned long windowStartTime = 0; unsigned long now = millis(); if (now - windowStartTime > SOLENOID_WINDOW) { // Start new window. windowStartTime = now; float dc = pidOutput / SOLENOID_WINDOW * 100.0; Serial.printf("Duty cycle: %.0f%%\n", dc); } if (pidOutput > now - windowStartTime) digitalWrite(SOLENOID_PIN, HIGH); else digitalWrite(SOLENOID_PIN, LOW); }