Wattwatcher 0.2 – Nå med templogging og sms varsling

1 Fikk gjort om koden litt slik at den nå enkelt kan støtte flere kWh målere, samt at jeg nå har en 1wire port.  Dette lar meg logge temperaturer på sensorer(DS18B20) i hele huset på kun 1 ledningspar i en cat5 kabel. Kabelen kan ha en lengde på opptil 300m.

Les mer om 1Wire Templogging med Arduino

Jeg har også laget 3.5mm jack kontakter til LDR sensor, lcd og  1Wire nettet. Dette satt jeg på et custom  ProtoShield som nå kan stackes mellom Arduino og Ethernet shieldet. DSC_0123

Alle delene den består av:  DSC_0125

“Ferdig” montert og i drift ser det slik ut.. Henger i kablene enn så lenge.

1

LDR montert på hovedstrømmåleren:

4

Det hender jo at internettlinjen detter ned, eller at strømmen går,  i disse tilfellene blir det ikke registrert noe til databasen. Om det går 5 min eller mer mellom to registreringer så får jeg en sms om det. Og etter ytterligere en time så en ny. Dette er løst vha et php script som sjekker differanse mellom tidspunkt for siste rad i basen mot nåværende tidspunkt. Er dette mer enn 5 min, så sendes SMS, og jeg setter et “flagg” for at wattwatcher er offline. På den måten slipper jeg å varsles flere ganger for samme feil. Denne sjekken kjører via cron hvert 5 minutt, og neste gang den oppdager ny registrering så fjernes “offline” flagget, og sms sendes om at den nå er oppe å kjører.

php kode for sms varsling

<?
include ("db.php");
$watts = $_GET['watt'];
$pw = $_GET['pw'];
$temp1 = $_GET['temp1'];
$temp2 = $_GET['temp2'];
$mail_to="espen@gmx.no";
$mail_from="Powermeter";
$mail_sub="No update last 2 minutes";
$mail_mesg="Sjekk kWh tellern!!!";
$time = date("Y-m-d H:i:s");

$link = mysql_connect($mysql_host, $mysql_user, $mysql_pass) or die("Feil x01");

if ( $link ) {
mysql_select_db($mysql_db) or die(mysql_error());

$result = mysql_query("SELECT * FROM 14418_usage order by id DESC LIMIT 0,1 ") or die(mysql_error());
while($row = mysql_fetch_array($result))
{
$lastdate = $row['time'];

}

//Sjekker først om 5min sms er sendt.
$result2 = mysql_query("SELECT * FROM config where id= 1") or die(mysql_error());
while($row2 = mysql_fetch_array($result2))
{

$status5 = $row2['value'];

}

//Sjekker så om 60min sms er sendt.
$result2 = mysql_query("SELECT * FROM config where id= 2") or die(mysql_error());
while($row2 = mysql_fetch_array($result2))
{

$status60 = $row2['value'];

}

echo"lastupdate: ".$lastdate."&lt;br&gt;";

//$curtime = date("Ymdhi", strtotime(date("Y-m-d h:i:s")));
$curtime = time();
echo"curtime: ".$curtime."&amp;amp;amp;amp;amp;amp;amp;lt;br&amp;amp;amp;amp;amp;amp;amp;gt;";
$lastupdate = strtotime($lastdate);
echo"lastupdate stamp: ".$lastupdate."&amp;amp;amp;amp;amp;amp;amp;lt;br&amp;amp;amp;amp;amp;amp;amp;gt;";
$diff =  $curtime - $lastupdate;
echo "Det er : ". $diff ." sekunder siden oppdatering.&amp;amp;amp;amp;amp;amp;amp;lt;br&amp;amp;amp;amp;amp;amp;amp;gt;";

}
if ($diff &amp;amp;amp;amp;amp;amp;amp;lt; "300") // Vi har ferske data, sjekker om sms er satt til sendt, hvis den er det så nuller vi flagget, slik at den kan sendes på nytt neste gang vi har feil..
{
if ($status5 == "1")
{
mysql_query("UPDATE config SET `value` = '0' WHERE `id` =1") or die(mysql_error());
$msg = "[online] last update: ";
$sendurl = sendsms($msg, $lastdate);
if (file_get_contents($sendurl)) {

echo "&amp;amp;amp;amp;amp;amp;amp;lt;BR&amp;amp;amp;amp;amp;amp;amp;gt;SMS er sendt!! OK&amp;amp;amp;amp;amp;amp;amp;lt;br\&amp;amp;amp;amp;amp;amp;amp;gt;";
//echo $sendurl;
}

else
{
echo "error while sending";
}

}

if ($status60 == "1")
{
mysql_query("UPDATE config SET `value` = '0' WHERE `id` =2") or die(mysql_error());
$msg = "[online] last update: ";
$sendurl = sendsms($msg, $lastdate);
if (file_get_contents($sendurl)) {

echo "&amp;amp;amp;amp;amp;amp;amp;lt;BR&amp;amp;amp;amp;amp;amp;amp;gt;SMS er sendt!! OK&amp;amp;amp;amp;amp;amp;amp;lt;br\&amp;amp;amp;amp;amp;amp;amp;gt;";

}

else
{
echo "error while sending";
}
}
}

if ($diff &amp;amp;amp;amp;amp;amp;amp;gt; "300") // Mer enn 5 min siden siste oppdatering. Vi sender sms

{

if ($status5 == "0") // SMS er ikke sendt, så vi sender nå.
{

$msg = "[5min]Ingen update siden: ";
$sendurl = sendsms($msg, $lastdate);
if (file_get_contents($sendurl)) {

echo "&amp;amp;amp;amp;amp;amp;amp;lt;BR&amp;amp;amp;amp;amp;amp;amp;gt;SMS er sendt!! OK&amp;amp;amp;amp;amp;amp;amp;lt;br\&amp;amp;amp;amp;amp;amp;amp;gt;";
//echo $sendurl;
}

else
{
echo "error while sending";
}

// Må nå lagre i DB at sms er sendt.
mysql_query("UPDATE config SET `value` = '1' WHERE `id` =1") or die(mysql_error());
}

}

if ($diff &amp;amp;amp;amp;amp;amp;amp;gt; "3600") // Mer enn 1 time siden siste oppdatering. Vi sender mail og sms på nytt.
{

$msg = "[60min] Ingen update siden: ";
$sendurl = sendsms($msg, $lastdate);
if (file_get_contents($sendurl)) {

echo "&amp;amp;amp;amp;amp;amp;amp;lt;BR&amp;amp;amp;amp;amp;amp;amp;gt;SMS er sendt!! OK&amp;amp;amp;amp;amp;amp;amp;lt;br\&amp;amp;amp;amp;amp;amp;amp;gt;";
//echo $sendurl;
}

else
{
echo "error while sending";
}

if(mail($mail_to,$mail_from,$mail_sub,$mail_mesg))
{
echo "&amp;amp;amp;amp;amp;amp;amp;lt;span class='red'&amp;amp;amp;amp;amp;amp;amp;gt;E-mail has been sent successfully from $mail_from to ###### &amp;amp;amp;amp;amp;amp;amp;lt;/span&amp;amp;amp;amp;amp;amp;amp;gt;";
}
else
echo "&amp;amp;amp;amp;amp;amp;amp;lt;span class='red'&amp;amp;amp;amp;amp;amp;amp;gt;Failed to send the E-mail from $mail_from to #######&amp;amp;amp;amp;amp;amp;amp;lt;/span&amp;amp;amp;amp;amp;amp;amp;gt;";
}

function sendsms($msg, $lastupdate)
{
$userid="sensur";
$time = date('Y-m-d H:i:s');
$password="sensur";
$last = $lastupdate;
$sender="WattWatcher";
$receiver="dittmobilnr;
$message= "[".$time ."]". $msg."[".$last."]";
$url="http://kjappsms.no/sms/SendSms.aspx?id=".$userid."&amp;amp;amp;amp;amp;amp;amp;amp;Password=".$password."&amp;amp;amp;amp;amp;amp;amp;amp;Sender=".$sender."&amp;amp;amp;amp;amp;amp;amp;amp;Recipient=".$receiver."&amp;amp;amp;amp;amp;amp;amp;amp;Msg=".urlencode($message);
return $url;
}

?&amp;amp;amp;amp;amp;amp;amp;gt;

Koden for Arduinoen er nå slik:

#include <OneWire.h>
#include <DallasTemperature.h>
#include <SoftwareSerial.h>
#include <Ethernet.h>
#define rxPin 2
#define txPin 3
#define ONE_WIRE_BUS 5
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress utesensor = { 0x28, 0x7E, 0xF9, 0x5E, 0x2, 0x0, 0x0, 0x42 }; // loddet på 3.5mm
// DeviceAddress innetemp = { 0x28, 0xF0, 0x12, 0x5F, 0x02, 0x0 , 0x0, 0x9E }; //  på hylla
DeviceAddress innesensor = { 0x28,0x2A,0xDE,0x5E,0x02,0x00,0x00,0x19 }; // I BODEN.
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 10, 0, 0, 177 };
byte gw[] = {10,0,0,101};
byte server[] = { 88,87,42,5 }; // gmx.no
byte subnet[] = { 255, 255, 255, 0 };

SoftwareSerial lcdSerial =  SoftwareSerial(rxPin, txPin);
int ledPin = 6;
int avgwatt = 5;
int switchPin = 7;
const int numReadings = 20;
unsigned long period_start;
unsigned long period_length = 57000;
unsigned long period_total;
unsigned long period_stop;
unsigned long run = 0;
int period_average;
int period_counter;
float itemp;
float utemp;

void setup()
{
  Serial.begin(9600);
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  pinMode(switchPin, INPUT);
  pinMode(ledPin, OUTPUT);
  lcdSerial.begin(9600);
  sensors.begin();
  sensors.setResolution(innesensor, 12);
  sensors.setResolution(utesensor, 12);
}
void loop()
{
  sensors.requestTemperatures(); // Send the command to get temperatures
  lcdcls();
  period_total = 0;
  period_counter = 0;
  period_start = millis();
  period_stop = period_start + period_length;
  if (run > 0) {
     lcdgoTo(0);
     lcdSerial.print(avgwatt);
     lcdSerial.print(" Current.  ");
     lcdgoTo(17);
     lcdSerial.print(period_average);
     lcdSerial.print(" Average.  ");

      }
      else {        // First run.. write no data.
     lcdgoTo(0);
     lcdSerial.print("No data.");
     lcdgoTo(17);
     lcdSerial.print("No data.");

      }

  while( millis() <period_stop) {
      lcdgoTo(0);
      avgwatt = getAvgWatt();   // returns average watt
      Serial.print("Snitt er: ");  // for debugging
      Serial.println(avgwatt);
      lcdSerial.print(avgwatt);
      lcdSerial.print(" Current.  ");
      // timedAction.check(); // check if its time to do the Senddata()
      period_total += avgwatt;
      period_counter += 1;

  }    // Etter at period- er utløpt. Dvs 1min. Vi regner ut avg og skriver til Linje2 på lcd.
   lcdcls();
   period_average = 0;
   period_average = period_total / period_counter;
   lcdgoTo(17);
   lcdSerial.print(period_average);
   lcdSerial.print(" Average.  ");
   sensors.requestTemperatures(); // Send the command to get temperatures
   delay(750);
   itemp = getTemp(innesensor);
   utemp = getTemp(utesensor);

   sendWatt();
   run +=1;
}

void sendWatt(){
  Ethernet.begin(mac, ip, gw, subnet);
  Client client(server, 80);
//   delay(1000);
  Serial.println();
  Serial.println("Initiates connection...");
  Serial.println("Connecting...");
  if (client.connect()) {
    Serial.println("Connected!");
    client.print("GET http://gmx.no/?watt=");
    client.print(period_average);
    client.print("&pass=*******&temp1=");
    client.print(itemp);
    client.print("&temp2=");
    client.print(utemp);
//    client.print(sensors.getTempC(innetemp));
    client.println(" HTTP/1.1");
    client.println("Host: www.gmx.no");
    client.println();
 //   delay(1000);             // Lar webserver rekke å returnere data før vi prøve å lese det ut.
  //  while(client.available()) {
  //    char c = client.read();
   //   Serial.print(c);
   //   }
    } else {
   Serial.println("Connection failed");
  }
   //stopper client
   client.stop();
    while(client.status() != 0) {
    delay(5);
    }

}  

int getAvgWatt(){

  int watt = 0;
  int index = 0;
  float average= 0;
  float total = 0;
  int old_val = 0;
  unsigned long current_time = 0;
  unsigned long last_time = 0;
  float delayarray[numReadings];
  float pulsedelay = 0;
  last_time = millis();
  int val = LOW;
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
  {
     delayarray[thisReading] = 0;
  }
   while (index < numReadings){

       val = (digitalRead(switchPin));              // Reads value  high/low and saves it
       if ((val == HIGH) && (old_val == LOW)) {     // We have light, lets read the time, and value.
       current_time = millis();                         // Current time
       pulsedelay = current_time - last_time;      	 // Delay since last pulse
       pulsedelay = pulsedelay / 1000;         		// I want seconds, not ms
       digitalWrite(ledPin, HIGH);                  // Blinks the LED
       delayarray[index] = pulsedelay;              // Add the value to the array
       old_val = val;        // Sets old_val high
       Serial.println(pulsedelay);					// THIS IS THE ONE THAT KEEPS IT FROM FREEZING

       last_time = current_time;                    // for the next whileloop-cycle to know the next delay.
       index +=1;    

   }
   else {
       digitalWrite(ledPin, LOW); // No light detected
       old_val = val;
       }
  }  

  for (int i = 1; i< numReadings;i++){    //Skip the first value in the array, since millis() from the start is off.
     total = total + delayarray[i];
   		}
     average = total / (numReadings-1); // Minus 1 since we skipped the first value in the array.

     watt = 360 / average; // 360 / average delay gives us current powerconsumption in watts.
     total = 0;  // for the next cycle
     average= 0; // for the next cycle    

     // Empty out the array. Not sure if this is needed.
     // for (int y = 0; y < numReadings; y++) {
     //delayarray[y] = 0;
     //}
     return watt;
}

//SerialLCD Functions
void selectLineOne(){  //puts the cursor at line 0 char 0.
   lcdSerial.print(0xFE, BYTE);   //command flag
   lcdSerial.print(128, BYTE);    //position
}
void selectLineTwo(){  //puts the cursor at line 2 char 0.
   lcdSerial.print(0xFE, BYTE);   //command flag
   lcdSerial.print(192, BYTE);    //position
}

void lcdcls(){
  lcdgoTo(0);
  lcdSerial.print("                                ");
}

void clearLCD(){
   lcdSerial.print(0xFE, BYTE);   //command flag
   lcdSerial.print(0x01, BYTE);   //clear command.
}
void backlightOn(){  //turns on the backlight
    lcdSerial.print(0x7C, BYTE);   //command flag for backlight stuff
    lcdSerial.print(157, BYTE);    //light level.
}
void backlightOff(){  //turns off the backlight
    lcdSerial.print(0x7C, BYTE);   //command flag for backlight stuff
    lcdSerial.print(128, BYTE);     //light level for off.
}
void lcdgoTo(int position) { //position = line 1: 0-19, line 2: 20-39, etc, 79+ defaults back to 0
if (position<16){
  lcdSerial.print(0xFE, BYTE);   //command flag
  lcdSerial.print((position+128), BYTE);    //position
  }
  else if (position<32)
   {
   lcdSerial.print(0xFE, BYTE);   //command flag
   lcdSerial.print((position+47+128), BYTE);    //position
}
else { lcdgoTo(0); }
} 

// Henter temp fra gitt sensor.
float getTemp(DeviceAddress deviceAddress)
{
  float tempC = sensors.getTempC(deviceAddress);
  return tempC;
}
Dette innlegget ble publisert i Elektronikk, Programmering med stikkord , . Bokmerk permalenken.

2 kommentarer til Wattwatcher 0.2 – Nå med templogging og sms varsling

  1. Tunlid sier:

    Veldig flott prosjekt :)
    Har du noe mere informasjon over utstyret du bruker og verktøy som brukes ?

  2. Espen sier:

    @Tunlid
    Heisann, kan skrive litt om det ja. I utganspunktet kommer man langt med en loddebolt :)
    Utstyret kjøpet jeg stort sett fra sparkfun.com, men finner en del på elfa/clas ohlson også.

    Noe spesielt du tenkte på?

Legg igjen et svar

Din e-post vil ikke bli publisert. Obligatoriske felt er merket med *

*

Du kan bruke disse HTML-kodene og -egenskapene: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>