Arduino-Bastelei: Die smarte(re) Waschmaschine (Update)

Es gibt ein Update zum meinem Waschmaschinenprojekt. Zur Erinnerung: Es ging darum, bei einer recht alten Waschmaschine eine Benachrichtigung am Handy zu bekommen, sobald der Waschvorgang beendet ist.

Die Spielerei hat anfangs recht gut funktioniert, im Laufe der Zeit jedoch immer schlechter. Meine Erklärung: Der Vibrationssensor hat der Belastung nicht standgehalten. Der erste Sensor ging wirklich kaputt, ein zweiter wurde auch laufend schlechter. Schlechter bedeutet, dass die Werte immer mehr streuten und daher das zeitliche Vibrationsprofil, über das der letzte Schleudervorgang und damit das Ende des Waschvorgangs detektiert wurde, immer verrauschter und uneindeutiger wurde. Es gab Fehlalarme.

3-Achsen-Beschleunigungssensor GY-61

Über ein anderes Bastelprojekt bin ich dann auf einen einfachen 3-Achsen-Beschleunigungssensor gestoßen, den GY-61. Der gibt an drei analogen Ausgängen einfach die Beschleunigung für drei orthogonale Achsen (x, y, z) aus. Im Prinzip so ein Teil, welches heute in jedem Smartphone z.B. die Bildschirmorientierung steuert. Gravitation ist ja auch nichts anderes als eine Beschleunigung; dreht man das Handy, dann wirkt diese Beschleunigung (zumindest anteilig) in eine andere Richtung.

Ich habe nun den alten Vibrationssensor durch den neuen Beschleunigungssensor ersetzt. Von den drei Achsen kann ich allerdings nur ein einzige nutzen, weil der Wemos D1 mini nur einen analogen Eingang bietet. Hier ein paar Bilder vom Umbau:

Die Werte, die der Sensor in den drei Schleuderphasen der Waschmaschine liefert sind um Welten besser als das, was der Vibrationssensor jemals geliefert hat. Hier der Plot eines typischen Waschvorgangs:

Die Werte werden für mich zur Kontrolle an meinen Raspberry Pi geschickt und mit Hilfe der Bibliothek dygraphs geplottet. Blau: Beschleunigung. Rot: Der Schwellwert. Gelb: Dauer über dem Schwellwert. Rot: Auslösen der Benachrichtigung.

Man sieht hier schön, dass der letzte Schleudergang stärker und vor allem länger ist als die ersten beiden. Seit dem Einbau des neuen Sensors wurde damit das Ende des Waschvorgangs hundertprozentig richtig erkannt.

Ach ja, und hier noch der aktualisierte Code, falls der jemanden interessiert:

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>


// PIN config:
#define PinVibration A0


// timing varaibles:
unsigned long delay_between_measurements = 50;    // ms
unsigned long averaging_time             = 4500;  // ms
unsigned long time_between_data_points   = 5000;  // ms   => 12 measurement points per minute
unsigned long notification_delay         = 4;     // min

// other variables:
double        vibration                 = 0.0;     // vibration value
double        vibration_log_thres       = 20.0;     // if vibration is higher than this value a log entry is created
double        vibration_thres           = 100.0;   // if vibration is higher than this value the last vibration_last[] entry is set to 1
bool          vibration_last            [28];      // => array over the last 2.xx minutes (depends on variable time_between_data_points)
unsigned long means                     = 0;       // number of means per measurement
unsigned long notification_delay_start  = 0;       //start time of notification delay (milliseconds)

// WIFI credentials:
const char* wifi_ssid     = "MY_SSID";
const char* wifi_password = "MY_WIFI_PASSWORD";
 
// define URLs (BTW: use HTTP instead of HTTPS!):
String URL_log            = "http://MY_URL/waschmaschine/";
String URL_notification[] = {
                            "http://maker.ifttt.com/trigger/waschmaschinefertig/with/key/MY_KEY_1",
                            "http://maker.ifttt.com/trigger/waschmaschinefertig/with/key/MY_KEY_2",
                            };
// we need this line to walk through the string loop using "ArraySize()":
template< typename T, size_t N > size_t ArraySize (T (&) [N]){ return N; }    // see http://forum.arduino.cc/index.php?topic=157398.0
 
 
void setup() {
  
  // set PINs and PIN modes:
  pinMode(PinVibration, INPUT);
  pinMode(BUILTIN_LED, OUTPUT);

  // start serial output:
  Serial.begin(115200);

  // connect to WiFi network:
  connect2Wifi();
}



void loop() {

  // measure a vibration value:
  measure_vibration();

  // log the vibration value:
  if (vibration > vibration_log_thres || sum_over_thres() >= 1) {
    send_log();
  }

  // start notification delay if end of long vibration is detected:
  if (notification_delay_start == 0 && sum_over_thres() == sizeof(vibration_last)) {
    notification_delay_start = millis();
    Serial.println("[Notification] End of spinning detected!");
    Serial.println("[Notification] Start sending a notification in " + (String)notification_delay + " minutes.");
  
  }

  // send notification if end of notification delay is reached:
  if (notification_delay_start > 0 && millis() - notification_delay_start >= notification_delay * 60 * 1000) {
    notification_delay_start = 0;
    send_notification();
  }

  // wait rest of the time:
  delay(time_between_data_points - averaging_time);

}





///////////////////// function: measure the vibration value 
void measure_vibration() {
  Serial.println("=================================================================================");
  Serial.printf("[Vibration] Starting vibration measurement for %.1f seconds", averaging_time / 1000.);

  vibration = 0;
  means = 0;
  unsigned long starttime = millis();
  
  int x = 0;
  int xlast = 0;
  int xdiff = 0;
  while (millis() - starttime < averaging_time) { means ++; if (means % 10 == 0) Serial.print("."); x = analogRead(PinVibration); xdiff = abs(x - xlast); vibration = vibration + (xdiff - vibration) / means; xlast = x; delay(delay_between_measurements-10); } // explanation: // we use an bool array that contains zeros. // with every measurement the values of the bool array are shifted one step to the end // if a vibration measurement gives a value larger than the threshold => write a 1 to the first position of the bool array.
  // if the washing machine is spinning the array is filled with ones.
  // if the sum over the array values exceeds a defined value the notifications are sent
  shift_vibration_array();
  if (vibration >= vibration_thres) {
    vibration_last[0] = 1;
  }

  Serial.println();
  Serial.print(  "[Vibration] vibration           = "); Serial.print(vibration); Serial.println();
  Serial.print(  "[Vibration] vibration_log_thres = "); Serial.print(vibration_log_thres); Serial.println();
  Serial.print(  "[Vibration] vibration_thres     = "); Serial.print(vibration_thres); Serial.println();
  Serial.printf( "[Vibration] means               = %i\n", means);
  Serial.println("[Vibration] vibration_last      = " + gen_vibration_string());
  Serial.println("[Vibration] progress             = " + (String)sum_over_thres() + "/" + (String)sizeof(vibration_last));

}


///////////////////// function: send notification(s) 
void send_notification() {

  // Serial.println("[Notification] End of spinning detected!");
  // Serial.println("[Notification] Start sending a notification in " + (String)notification_delay + " minutes.");
  Serial.println("[Notification] Sending the notification(s).");
  //delay(notification_delay * 60 * 1000);

  // send notifications:
  for (int i = 0; i < ArraySize(URL_notification); i++) {
    Serial.println("[Notification] Sending notification #" + (String)(i+1) + ":");
    send_HTTP_request(URL_notification[i]);
  }

  // reset the vibration array (to avoid multiple alarms):
  for (int i = 0; i < sizeof(vibration_last); i++) { vibration_last[i] = 0; } } ///////////////////// function: send log values to server void send_log() { send_HTTP_request(URL_log + "?means=" + (String)means + "&vibration=" + (String)vibration + "&vibration_log_thres=" + (String)vibration_log_thres + "&vibration_thres=" + (String)vibration_thres + "&vibration_last=" + gen_vibration_string() + "&sum_over_thres=" + (String)sum_over_thres() + "&mac=" + WiFi.macAddress() + "&hostname=" + WiFi.hostname() + "&ip=" + WiFi.localIP().toString() + ""); } ///////////////////// function: send a http request void send_HTTP_request(String url) { HTTPClient http; Serial.println("[HTTP] Request URL: " + url); http.begin(url); // start connection and send HTTP header int httpCode = http.GET(); if (httpCode > 0) { // httpCode will be negative on error
    Serial.printf("[HTTP] Return code: %d\n", httpCode);

    if (httpCode == HTTP_CODE_OK) { Serial.println(http.getString()); }
  }
  else {
    Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
  }

  http.end();
}


///////////////////// function: shift the values of the vobration array
void shift_vibration_array() {
  // move all array elements one step to the end
  // the first element is set to zero
  for (int i = sizeof(vibration_last) - 1; i > 0; i--) {
    vibration_last[i] = vibration_last[i - 1];
  }
  vibration_last[0] = 0;
}


///////////////////// function: calculate the sum of the vibration array
int sum_over_thres() {
  // calculate the sum of values 1 in the vibration array
  int vibration_sum = 0;
  for (int i = 0; i < sizeof(vibration_last); i++) {
    vibration_sum += vibration_last[i];
  }
  return vibration_sum;
}

///////////////////// function: return the values of the vibration array as string 
String gen_vibration_string() {
  
  String vibration_string = "";
  for (int i = 0; i < sizeof(vibration_last); i++) {
    vibration_string = vibration_string + (String)vibration_last[i];
  }
  return vibration_string;
}


///////////////////// function: establish the WiFi connection 
void connect2Wifi() {
  Serial.println();
  Serial.printf("\n[WiFi] Connecting to SSID '%s' ", wifi_ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(wifi_ssid, wifi_password);

  while (WiFi.status() != WL_CONNECTED) {
    digitalWrite(BUILTIN_LED, LOW);
    delay(100);
    Serial.print(".");
    digitalWrite(BUILTIN_LED, HIGH);
    delay(100);
  }
  Serial.println(" Connected!");
  Serial.println("[WiFi] Hostname:  " + WiFi.hostname());
  Serial.println("[WiFi] MAC:       " + WiFi.macAddress());
  Serial.println("[WiFi] IP:        " + WiFi.localIP().toString());
  Serial.println();
  
  digitalWrite(BUILTIN_LED, LOW);
}



Eine Reaktion auf “Arduino-Bastelei: Die smarte(re) Waschmaschine (Update)


    Warning: in_array() expects parameter 2 to be array, string given in /homepages/u11825/dasaweb_de/wp-content/plugins/semantic-linkbacks/includes/class-linkbacks-walker-comment.php on line 25

    Warning: in_array() expects parameter 2 to be array, string given in /homepages/u11825/dasaweb_de/wp-content/plugins/semantic-linkbacks/includes/class-linkbacks-walker-comment.php on line 25

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.