Läsa av och logga elmätare med arduino.

Planering och tankar kring eventuella framtida projekt.
Användarvisningsbild
ochkl0620
Inlägg: 4852
Blev medlem: 9 maj 2010, 23:34:56
Skype: challe.claesson
Ort: Näsåker Västernorrland
Kontakt:

Läsa av och logga elmätare med arduino.

Inlägg av ochkl0620 »

Tjohopp!
Sedan vi blev med hus har jag börjat intressera mig för elförbrukningen...
Skulle vilja logga elförbrukningen genom att läsa av blinkfrekvensen på elmätaren med Arduino.
Till att börja med kan jag nöja mig med att bara se aktuell förbrukning för att slippa krångla med RTC kretsar och sånt.
Tanken är helt enkelt, en fotoresistor (LDR), arduino och en HD44780 2*16 LCD :)
Någon som har en lösning?
Användarvisningsbild
olalofberg
Inlägg: 230
Blev medlem: 5 november 2014, 19:00:57
Ort: Kristdala

Re: Läsa av och logga elmätare med arduino.

Inlägg av olalofberg »

larsolsson
Inlägg: 10
Blev medlem: 3 februari 2014, 17:11:25

Re: Läsa av och logga elmätare med arduino.

Inlägg av larsolsson »

skorpion
Inlägg: 72
Blev medlem: 21 augusti 2008, 21:39:13
Ort: Falun

Re: Läsa av och logga elmätare med arduino.

Inlägg av skorpion »

Jag har gjort en sådan läsare.

Tillvägagångssättet var att läsa av 10st blinkningar och mäta tiden mellan dem. Gör man tvärtom och mäter blinkningar över tid så riskerar man att dela en blinkning i 2 olika tidsintervaller. Dvs en blinkningen blir räknad 2ggr.
Kretsen är inte speciellt avancerad, men jag har en esp8266 wifi modul som sänder datan till en webserver som sparar det i en mysql-databas. Sedan har jag ett php-skript som läser från databasen och presenterar datan på lämpligt sätt. Databasen blir snabbt full med data, då jag har en databaspost per 10/blinkningar. Det blir en del på ett par dagar. Så då låter jag skriptet som sparar datan i databasen att gå igenom data som är äldre (typ 2veckor eller nåt) och klumpar ihop allt som är under samma timme. Så max 24 poster/dygn=~8760/år.

I min kod så är den ju anpassad en del för esp8826 och det var tänkt att när den inte får kontakt med webservern så ska den spara (bygga på) variablerna tills den får kontakt med servern. Vanligtvis skickar den blinkningar(10st) tillsammans med tid efter 10 uppnådda blinkningar, men tanken vara alltså att vid bruten serverkontakt bygga på variablerna tills den får kontakt, men denna funktion tror jag inte fungerar i min kod. Har inte orkat testa nå mera då jag blev pappa mitt i projektet så tiden blev lite mindre :)

Här är iaf källkoderna

Arduino-kod

Kod: Markera allt

//--esp8266--//
#include <SoftwareSerial.h>
#define SSID ""
#define PASS ""
#define IP "HOST" //your servername
String GET="GET energyMeter.php";
//GET energyMeter.php?time=12345&count=10
SoftwareSerial esp8266(10, 11); // RX, TX
bool sendOk=true;
int maxFailedAttempts=10;
int failedAttempts;
//--esp8266--//

//--energyMeter--// mysql> select ((60*60)/(avg(time)/10/1000))/1000*(56.14/100) from energyMeter; +------------------------------------------------+

int lightPin=0;
int ledPin=7;
int meterLed;
int meterLedHigh=75;
int currentState=LOW;
int wasLow=2;
int numFlashes=0;
int dbFlashes;
unsigned long timeInit=0;
unsigned long timeStart=0;
unsigned long timeStop=0;
unsigned long timeSpan=0;
unsigned long timeLast=0;
unsigned long tcpWait=0;
unsigned long split=0;
//--energyMeter--//

void setup(){
  Serial.begin(9600);
//--esp8266--//
  esp8266.begin(9600);
  sendDebug("AT");
  delay(1000);
  if(esp8266.find("OK")){
    Serial.println("RECEIVED: OK");
    connectWiFi();
  }
//--esp8266--//

//--energyMeter--//
  pinMode(ledPin, OUTPUT);
  timeInit=millis();
//--energyMeter--//
}

void loop(){
//--energyMeter--//
  meterLed=analogRead(lightPin);
  //Serial.println(meterLed);
  if(meterLed>meterLedHigh){
    currentState=HIGH;
    if(wasLow==2){
      timeStart=millis();
      //timeLast=timeStart;
      Serial.println("Börja räkna för den såg HIGH");
      Serial.print("start_time: ");
      Serial.println(timeStart);
      wasLow=0;
    }
  }
  else{
    currentState=LOW;
    if(wasLow==0){
      wasLow=1;
    }
  }

  split=millis()-timeLast;
  if(currentState==HIGH && wasLow==1 && split>1000){
    digitalWrite(ledPin,HIGH);
    numFlashes++;
    Serial.print("num: ");
    Serial.println(numFlashes);
    Serial.print("Split: ");
    Serial.println(split);
    if(split<1000){
//      Serial.println("split var kort...");
    }
    timeLast=millis();
    if(numFlashes==10){
      timeStop=millis();
      timeSpan+=(timeStop-timeStart);
      Serial.print("Time stop: ");
      Serial.println(timeStop);
      Serial.print("Interval: ");
      Serial.println(timeSpan);
      //updateDb(interval,numFlashes);
      if(dbFlashes==0){
        timeStart=timeStop;
      }
      dbFlashes+=numFlashes;
      //numFlashes=0;
      sendOk=false;  //initiate httpRequest
      Serial.println("Send http request! :)");
    }
    wasLow=false;
    currentState=LOW;
  }
  else{
    digitalWrite(ledPin,LOW);
  }
//--energyMeter--//

//--esp8266--//
  if(sendOk==false && millis()>=(tcpWait+4000)){
    Serial.println("Could not send, retrying...");
    //retry 20 times, instead add next 10counts to same new int that is included in updateDb-call
//    updateDb(timeSpan,numFlashes);
    updateDb(String(timeSpan),String(dbFlashes));
  }
  else{
    //Serial.println("(Successfully sent earlier) Waiting for sendOk=false to resend");
  }
  //delay(2000);
//--esp8266--//
  delay(100);
}

//--esp8266--//
void updateDb(String time,String count){
  Serial.print("Intention was to send: ");
  Serial.print(count);
  Serial.print(" : ");
  Serial.println(time);
  String cmd="AT+CIPSTART=\"TCP\",\"";
  cmd+=IP;
  cmd+="\",80";
  sendDebug(cmd);
  tcpWait=millis();
  do{
    if(esp8266.find("CONNECT")){
      Serial.println("RECEIVED: TCP Connected");
      cmd=GET;
      cmd+="?time="+time;
      cmd+="&count="+count;
    cmd+="\r\n";
      esp8266.print("AT+CIPSEND=");
      esp8266.println(cmd.length());
      Serial.println("AT+CIPSEND="+cmd.length());
      if(esp8266.find(">")){
        Serial.print(">");
        sendDebug(cmd);
        if(esp8266.find("OK")){
          Serial.println("RECEIVED: SEND OK");
          sendOk=true;
          //Send was OK, reset variables
          dbFlashes=0;
          numFlashes=0;
          timeSpan=0;
        }
        else{
          Serial.println("RECEIVED: NO SEND");
        }
      }
      else{
        sendDebug("AT+CIPCLOSE");
      }
    }
    else{
      Serial.println("RECEIVED: TCP Error");
    }
    Serial.println("breaking it");
    break;
  }
  while(millis()>=(tcpWait+2000));
}
//--esp8266--//


//--esp8266--//
void sendDebug(String cmd){
  Serial.print("SEND: ");
  Serial.println(cmd);
  esp8266.println(cmd);
} 
//--esp8266--//


//--esp8266--//
boolean connectWiFi(){
  sendDebug("AT+CWMODE=1");
  delay(1000);
  String cmd="AT+CWJAP=\"";
  cmd+=SSID;
  cmd+="\",\"";
  cmd+=PASS;
  cmd+="\"";
  sendDebug(cmd);
  delay(3000);
  if(esp8266.find("OK")){
    Serial.println("RECEIVED: OK");
    return true;
  }
  else{
    Serial.println("RECEIVED: Error");
    return false;
  }
}
//--esp8266--//
energyMeter.php

Kod: Markera allt

<?php
include("mysqlDB.php");
if($_GET["time"]!="" && $_GET["count"]!=""){
    $query="INSERT INTO energyMeter VALUES(".time().",".$_GET["time"].",".$_GET["count"].",false)";
    mysqli_query($link,$query)or die("ERROR");
    echo $_GET["time"]."_".$_GET["count"];
}
else{
//do nothing
}

$query="SELECT date as ts, date(from_unixtime(date)) as date, hour(from_unixtime(date)) as hour, sum(time) as secs, sum(count) as counts, combined FROM energyMeter WHERE from_unixtime(date)<(date(NOW())-INTERVAL 7 day) && combined=false GROUP BY date(from_unixtime(date)),hour(from_unixtime(date))";
$res=mysqli_query($link, $query);
while($row=mysqli_fetch_assoc($res)){
//echo "INSERT INTO energyMeter VALUES(".(floor($row["ts"]/3600)*3600).",".$row["secs"].",".$row["counts"].",true)";
    mysqli_query($link,"INSERT INTO energyMeter VALUES(".(floor($row["ts"]/3600)*3600).",".$row["secs"].",".$row["counts"].",true)");
}
//echo "DELETE FROM energyMeter WHERE from_unixtime(date)<(date(NOW())-INTERVAL 5 day) && combined=false";
mysqli_query($link,"DELETE FROM energyMeter WHERE from_unixtime(date)<(date(NOW())-INTERVAL 7 day) && combined=false");
?>
Hårdvaran är gjord efter någon av dessa:
https://www.google.se/search?q=arduino+light+sensor
Ingen avancerad krets alltså. (om man räknar bort esp8826)
Om du även vill veta hur 8826 är kopplad så kan jag skriva ner det.

Men som sagt, koden är inte verifierad till 100%, men för mig loggar den data iaf :P

MVH Niclas
Skriv svar