SHARE
TWEET

Code for washing machine monitoring using SCT-013-030 ver 2

hanpa Aug 19th, 2017 71 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <Arduino.h>
  2. #include <ESP8266WiFi.h>
  3. #include <ESP8266mDNS.h>
  4. #include "Adafruit_MQTT.h"
  5. #include "Adafruit_MQTT_Client.h"
  6. #include <ArduinoOTA.h>
  7. #include "/Users/hanpa/Dropbox/Hem/Arduino/common/credentials.h"
  8.  
  9. const char* version   = "WashingMachineMonitor 2.0";
  10. const char* date_name = "2017-08-19 Hans Palm";
  11.  
  12. // Hans Palm 2017
  13. // http://www.hobbyelektronik.nu/
  14. //
  15. // This code monitors the washing machine using a SCT-013-030 current transformer
  16. // on one of the electrical phases. SCT-013-030 returns AC of 1V for 30A so a small
  17. // circuit is needed to transform this to a voltage suitable for the analogue A0 input
  18. // on a Wemos D1 mini that has a rage from 0 - 3.3V.
  19. // A circuit and description of the projekt is available here:
  20. //   http://www.hobbyelektronik.nu/forum/viewtopic.php?f=13&t=42
  21. //
  22. // Max and min values of the current is logged during 1 second, the difference
  23. // of max - min is the maximum current span (max current amplitude) during that period.
  24. // This value is then used by a state machine to determine the status of
  25. // the washing machine. The logic will need to be adapted to a certain washing machine.
  26. // Use mqtt values for current span for checking your current levels during a washing cycle
  27. // and adapt the logic accordingly.
  28. //
  29. // The status is indicated using a RGB LED and a button is used to acknowledgement
  30. // of that the washing machine has finished and is waiting for emptying
  31. //
  32. // RGB LED Colours
  33. // Bright RED    - Not connected to WifFi/MQTT
  34. // Light Green   - Off
  35. // Light RED     - Inactive
  36. // RED           - Running
  37. // Blinking Blue - Waiting for press of acknowledge button
  38.  
  39. // The current state of washing machine is sent using mqtt each second
  40. // and also using separate mqtt message on the event of that the washing
  41. // machine is finished and when the acknowledgement button is pressed
  42.  
  43. /************************* WiFi Access Point *********************************/
  44.  
  45. #define WLAN_SSID       ssid
  46. #define WLAN_PASS       password
  47.  
  48. /***************************** MQTT settings *********************************/
  49. #define SERVER      mqtt_server
  50. #define SERVERPORT  mqtt_port              // use 8883 for SSL
  51. #define USERNAME    ""                     // Not used, from Adafruit.io Setup
  52. #define KEY         ""                     // Not used, from Adafruit.io Setup
  53.  
  54. /************************* OTA *********************************/
  55. #define OTA_HOST_NAME   "WashingMachineM"        // No _ in host names!
  56. const char* host = OTA_HOST_NAME;
  57.  
  58. // The follwing parameters are only required for fixed IP, otherwise uncomment, also uncomment WiFi.config(ip, gateway, subnet)
  59. //IPAddress ip(192, 168, 0, TBD);
  60. IPAddress gateway(192, 168, 0, 1);
  61. IPAddress subnet(255, 255, 255, 0);
  62.  
  63. /******************** RGB LED and button PIN definitions *********************/
  64. #define BUTTON_PIN D3
  65. #define RGB_R_PIN  D5
  66. #define RGB_G_PIN  D6
  67. #define RGB_B_PIN  D7
  68.  
  69. /******************** Types and values for monitoring ************************/
  70.  
  71. enum washingMachineStates {
  72.   Off,
  73.   Inactive,
  74.   Running,
  75.   WaitingForAcknowledge
  76. };
  77. washingMachineStates washingMachineState = Off;
  78.  
  79. // A measured current span above this value indicates a running machine
  80. #define TO_RUNNING_THRESHOLD 30
  81.  
  82. // Require some seconds above threshold before considered running to filter out power transients
  83. #define TIME_ABOVE_TO_RUNNING_THRESHOLD_BEFORE_RUNNING 3
  84.  
  85. // A measured current span below this value indicates an inactive machine, can be temporarily, e.g. filling up water
  86. #define TO_INACTIVE_THRESHOLD 20
  87.  
  88. // Time in seconds of Inactive before considered Not_Running
  89. #define TIME_IN_INACTIVE_BEFORE_NOT_RUNNING 180
  90.  
  91. // For keeping track of how long the current span has been above TO_RUNNING_THRESHOLD when in Off, to filter out transients
  92. int secondsInOffAboveToRunningThreshold = 0;
  93.  
  94. // For keeping track of how long the state has been Inactive. Stored value of millis() when Inactive was assigned.
  95. unsigned int startTimeInInactive = 0;
  96.  
  97. // Create an ESP8266 WiFiClient class to connect to the MQTT server.
  98. WiFiClient client;
  99. // or... use WiFiFlientSecure for SSL
  100. //WiFiClientSecure client;
  101.  
  102. // Setup the MQTT client class by passing in the WiFi client and MQTT server and login details.
  103. Adafruit_MQTT_Client mqtt(&client, SERVER, SERVERPORT, USERNAME, KEY);
  104.  
  105. /****************************** Feeds ***************************************/
  106.  
  107. // Setup feeds for publishing.
  108. Adafruit_MQTT_Publish mqttWashingMachineCurrentSpan1s = Adafruit_MQTT_Publish(&mqtt, USERNAME "WashingMachineCurrentSpan1s");
  109. Adafruit_MQTT_Publish mqttWashingMachineState = Adafruit_MQTT_Publish(&mqtt, USERNAME "WashingMachineState");
  110. Adafruit_MQTT_Publish mqttWashingMachineFinishedEvent = Adafruit_MQTT_Publish(&mqtt, USERNAME "WashingMachineFinishedEvent");
  111. Adafruit_MQTT_Publish mqttWashingMachineAcknowledgedEvent = Adafruit_MQTT_Publish(&mqtt, USERNAME "WashingMachineAcknowledgedEvent");
  112.  
  113. void MQTT_connect();
  114.  
  115. void OTA_setup() {
  116.   ArduinoOTA.setHostname(host);
  117.  
  118.   ArduinoOTA.onStart([]() {
  119.     String type;
  120. //    if (ArduinoOTA.getCommand() == U_FLASH)
  121.       type = "sketch";
  122. //    else // U_SPIFFS
  123. //      type = "filesystem";
  124.  
  125.     // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
  126.     Serial.println("Start updating " + type);
  127.   });
  128.   ArduinoOTA.onEnd([]() {
  129.     Serial.println("\nEnd");
  130.   });
  131.   ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
  132.     Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  133.   });
  134.   ArduinoOTA.onError([](ota_error_t error) {
  135.     Serial.printf("Error[%u]: ", error);
  136.     if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
  137.     else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
  138.     else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
  139.     else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
  140.     else if (error == OTA_END_ERROR) Serial.println("End Failed");
  141.   });
  142.   ArduinoOTA.begin();
  143. }
  144.  
  145. void setRedLED(uint8_t value) {
  146.   analogWrite(RGB_R_PIN, value);
  147. }
  148. void setGreenLED(uint8_t value) {
  149.   analogWrite(RGB_G_PIN, value);
  150. }
  151. void setBlueLED(uint8_t value) {
  152.   analogWrite(RGB_B_PIN, value);
  153. }
  154.  
  155. void setRGBLED (uint8_t R, uint8_t G, uint8_t B) {
  156.   setRedLED(R);
  157.   setGreenLED(G);
  158.   setBlueLED(B);
  159. }
  160.  
  161. void setup() {
  162.   Serial.begin(115200);
  163.   delay(10);
  164.  
  165.   // Button and RGB LED setup
  166.   pinMode(BUTTON_PIN, INPUT_PULLUP);
  167.   pinMode(RGB_R_PIN, OUTPUT);
  168.   pinMode(RGB_G_PIN, OUTPUT);
  169.   pinMode(RGB_B_PIN, OUTPUT);
  170.  
  171.   // Connect to WiFi access point.
  172.   Serial.println(); Serial.println();
  173.   Serial.print("Connecting to ");
  174.   Serial.println(WLAN_SSID);
  175.  
  176.   //WiFi.config(ip, gateway, subnet); // Only required for fixed IP
  177.   WiFi.begin(WLAN_SSID, WLAN_PASS);
  178.   while (WiFi.status() != WL_CONNECTED) {
  179.     setRGBLED(128,0,0);
  180.     delay(500);
  181.     Serial.print(".");
  182.   }
  183.   Serial.println();
  184.  
  185.   Serial.println("WiFi connected");
  186.   Serial.println("IP address: "); Serial.println(WiFi.localIP());
  187.  
  188.   OTA_setup();
  189. }
  190.  
  191. void loop() {
  192.   ArduinoOTA.handle();
  193.  
  194.   // Ensure the connection to the MQTT server is alive (this will make the first
  195.   // connection and automatically reconnect when disconnected).  See the MQTT_connect
  196.   // function definition further below.
  197.   MQTT_connect();
  198.  
  199.   // Process mqtt data
  200.   mqtt.processPackets(50);
  201.  
  202.   // ping the server to keep the mqtt connection alive
  203.   // NOT required if you are publishing once every KEEPALIVE seconds
  204.   /*
  205.   if(! mqtt.ping()) {
  206.    mqtt.disconnect();
  207.  }
  208.  */
  209.  
  210.  // Read current levels from analogue (A0) input during 1 second to determine min, max and current span (amplitude)
  211.  int max = 0;
  212.  int min = 1023;
  213.  unsigned int startTimeOfMeasuring = millis();
  214.  while (true) {
  215.    int v = analogRead(A0);
  216.    if (v > max) {
  217.      max = v;
  218.    }
  219.    if (v < min) {
  220.      min = v;
  221.    }
  222.    if ( (millis() - startTimeOfMeasuring) > 1000) {
  223.      break; // 1 second of reading A0 completed
  224.    }
  225.  
  226.    // Check for acknowledge button progress
  227.    if (washingMachineState == WaitingForAcknowledge) {
  228.      if( ( (millis()/200) % 2) == 0) {
  229.        setRGBLED(0,0,128);
  230.      } else {
  231.        setRGBLED(0,0,0);
  232.      }
  233.      // Wait for press of acknowledge button
  234.      if (digitalRead(BUTTON_PIN) == 0) {
  235.        mqttWashingMachineAcknowledgedEvent.publish(1);
  236.        washingMachineState = Off;
  237.        break;
  238.      }
  239.    }
  240.    // Free some time for network tasks and check request for OTA update
  241.    delay(10);
  242.    ArduinoOTA.handle();
  243.  }
  244.  
  245.  int currentSpan = max - min;
  246.  
  247.  // Publish current span value on MQTT
  248.  mqttWashingMachineCurrentSpan1s.publish(currentSpan);
  249.  
  250.  // Evaluate state
  251.  switch (washingMachineState) {
  252.  
  253.    case Off:
  254.    setRGBLED(0,1,0);
  255.    if (currentSpan > TO_RUNNING_THRESHOLD) {
  256.      // Filter out power transients, require vurrent span above threshold for some seconds before considered running
  257.      if (secondsInOffAboveToRunningThreshold >= TIME_ABOVE_TO_RUNNING_THRESHOLD_BEFORE_RUNNING ) {
  258.        washingMachineState = Running;
  259.        secondsInOffAboveToRunningThreshold = 0;
  260.      } else {
  261.        secondsInOffAboveToRunningThreshold++;
  262.      }
  263.    } else {
  264.      secondsInOffAboveToRunningThreshold = 0;
  265.    }
  266.    break;
  267.  
  268.    case Running:
  269.    setRGBLED(64,0,0);
  270.    if (currentSpan < TO_INACTIVE_THRESHOLD) {
  271.      startTimeInInactive = millis();
  272.      washingMachineState = Inactive;
  273.    }
  274.    break;
  275.  
  276.    case Inactive:
  277.    setRGBLED(1,0,0);
  278.    if ( (millis() - startTimeInInactive) > TIME_IN_INACTIVE_BEFORE_NOT_RUNNING*1000) {
  279.      // The washing machine has completed a washing cycle
  280.      // Publish the event of completion on MQTT
  281.      mqttWashingMachineFinishedEvent.publish(1);
  282.      washingMachineState = WaitingForAcknowledge;
  283.    } else if (currentSpan > TO_RUNNING_THRESHOLD) {
  284.      washingMachineState = Running;
  285.    }
  286.    break;
  287.  
  288.  }
  289.  
  290.  // Publish current state on MQTT
  291.  switch (washingMachineState) {
  292.    case Off:
  293.    mqttWashingMachineState.publish("Off");
  294.    break;
  295.    case Running:
  296.    mqttWashingMachineState.publish("Running");
  297.    break;
  298.    case Inactive:
  299.    mqttWashingMachineState.publish("Inactive");
  300.    break;
  301.    case WaitingForAcknowledge:
  302.    mqttWashingMachineState.publish("WaitingForAcknowledge");
  303.    break;
  304.  }
  305.  
  306. } // end of loop()
  307.  
  308. // Function to connect and reconnect as necessary to the MQTT server.
  309. // Should be called in the loop function and it will take care if connecting.
  310. void MQTT_connect() {
  311.   int8_t ret;
  312.  
  313.   // Stop if already connected.
  314.   if (mqtt.connected()) {
  315.     return;
  316.   }
  317.  
  318.   setRGBLED(128,0,0);
  319.  
  320.   Serial.print("Connecting to MQTT... ");
  321.  
  322.   while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
  323.     Serial.println(mqtt.connectErrorString(ret));
  324.     Serial.println("Retrying MQTT connection in 5 seconds...");
  325.     mqtt.disconnect();
  326.     delay(5000);  // wait 5 seconds
  327.   }
  328.   Serial.println("MQTT Connected!");
  329. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top