IP-camera zonder snapshot mogelijkheid, m.b.v. script toch een snapshot verkrijgen uit RTSP-stream!

Door ThinkPad op maandag 3 augustus 2015 11:56 - Reacties (11)
Categorie: Domotica, Views: 7.692

Edit: Met hartelijke dank aan Tweaker 'Yorick87' blijkt nu dat met een firmware upgrade de camera rechtstreeks een JPEG-snapshot kan uitspugen!
Zie: ThinkPad's Tweakblog: IP-camera zonder snapshot mogelijkheid, m.b.v. script toch een snapshot verkrijgen uit RTSP-stream! en ThinkPad's Tweakblog: IP-camera zonder snapshot mogelijkheid, m.b.v. script toch een snapshot verkrijgen uit RTSP-stream!


Tijdje terug een camera gekocht (TOP-201 mini IP-camera (§22.97)) om m'n voordeur in de gaten te houden. Handig om op afstand te zien dat de pakketbezorger voor de deur staat.
http://tweakers.net/ext/f/DfJMr27f5PljSaTQSuvk87R5/full.jpg

De camera levert een prima 720p beeld, maar heeft als nadeel dat hij alleen ONVIF en RTSP ondersteunt. Voor mijn doel zou ik graag een URL hebben waarmee ik rechtstreeks een (JPEG) snapshot kon opvragen. Helaas heeft de camera deze mogelijkheid niet.

Wel spuugt hij twee RTSP-streams uit die je bijv. in VLC kunt bekijken:

rtsp://IP_VAN_CAMERA//user=admin_password=_channel=1_stream=0.sdp (720p HD-kwaliteit)
rtsp://IP_VAN_CAMERA//user=admin_password=_channel=1_stream=1.sdp (VGA-kwaliteit)

Om toch een snapshot te verkrijgen, die ik dan op m'n telefoon kan bekijken als er wordt aangebeld, heb ik gekeken naar hoe je een snapshot van een RTSP-stream kunt maken. Dit schijnt met 'ffmpeg' goed mogelijk te zijn. Ik heb eerst geprobeerd om dit op m'n Synology NAS (DS114), waar ook Domoticz op draait, te regelen, maar de ffmpeg versie op de NAS wist geen raad met een RTSP-stream, hij kende het protocol niet. Ik heb geen zin om m'n NAS te gaan 'jailbreaken' (ipkg) dus daarom maar een Raspberry Pi gepakt die ik nog had liggen.

Daarmee geprobeerd om een snapshot te grabben van de stream en warempel, het lukte :D

Toen een script geklust:

Bash: snapshot.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/sh
today=`/bin/date '+%d-%m-%Y__%H-%M-%S'`;    #Used to generate filename
IP="192.168.4.20"                          # IP address Camera

#Ping IP-address of camera to see if it's online, otherwise we don't have to grab a snapshot
if ping -c 1 $IP > /dev/null ; then  

#Grab snapshot from RTSP-stream
/volume1/@appstore/MediaServer/bin/ffmpeg -rtsp_transport tcp -i 'rtsp://'$IP'/user=admin&password=&channel=1&stream=0.sdp' -f image2 -vframes 1 -pix_fmt yuvj420p /volume1/homes/admin/doorbellcam/Public/doorbell_snapshots/$today.jpeg

#Delete previous taken snapshots older than 7 days
find /volume1/homes/admin/doorbellcam/Public/doorbell_snapshots/ -name '*.jpeg' -mtime +7 -delete
else
   echo "Doorbell has just been pressed, but image is unavailable because camera is ofline"
fi


(Zie ook de discussie op het Domoticz forum)

Als ik nu 'snapshot.sh' aanroep op de commandline verschijnt er na enkele seconden een snapshot op de in het script ingestelde locatie 8)

Het blijkt dat op bijv. de Synology aanwezige 'ffmpeg' versie niet altijd support heeft voor een RTSP-stream. Op internet vond ik een workaround, de ffmpeg binary van een via de Package Center te installeren Synology package gebruiken. Er zijn meerdere mogelijkheden:
  • /volume1/@appstore/MediaServer/bin/ffmpeg
  • /volume1/@appstore/AudioStation/bin/ffmpeg
  • /volume1/@appstore/VideoStation/bin/ffmpeg
Het package hoeft niet te draaien, als het script maar bij de ffmpeg binary kan. In mijn geval bleek de standaard ffmpeg versie 1.0 te zijn, de versie die met het 'MediaServer' package kwam had versie 2.02 aan boord en daarmee werkte het wel :)

De camera is ook bruikbaar met het 'Surveillance Station' package op de Synology ('Generic ONVIF' en dan poort 8899 geloof ik) en heb geprobeerd om via de API van Surveillance Station een snapshot eruit te trekken. Dit werkte redelijk, maar de helft van de tijd kreeg ik geen plaatje terug en ook duurde het vrij lang voordat het snapshot tevoorschijn kwam. Voor mij geen serieuze optie dus.

Al met al is een IP-camera met alleen een RTSP-stream op deze manier toch weer wat breder in te zetten dan voor alleen het bekijken van de stream.
Ik heb in m'n router overigens wel al het verkeer van deze camera richting internet geblokkeerd. Volgens reviews wil het ding nog wel eens contact zoeken met servers op internet. Misschien is het heel onschuldig (tijd updaten via NTP of checken op nieuwe firmware), maar het idee staat mij niet echt aan.

P.S. Je kunt ook in de camera komen via Telnet, username: root en wachtwoord: xmhdipc
Doe daar zelf verder niks mee, maar leuk om te weten. De camera gebruikt de Hi3518 chipset. Op www.ipcamtalk.com is een uitgebreide review te vinden (zoek op "TOP-201 ipcamtalk" en je vind hem wel).

Deurbel ombouw naar 433Mhz

Door ThinkPad op maandag 3 augustus 2015 11:16 - Reacties (3)
Categorie: Domotica, Views: 5.629

Ik had al een tijdje m'n domoticasysteem (Domoticz) in gebruik, maar mistte eigenlijk nog de uitlezing van de deurbellen.

Deurbellen zeg je? Ja... Ik heb er namelijk twee omdat ik in een appartement woon. Beneden in het portiek heb ik een intercom bel + microfoon&luidspreker. Maar aan de galerij heb ik ook een deurbel zoals in de meeste huizen in NL (8V AC trafo, knopje naast de deur en een bel met zo'n hamertje).

Even gezocht (ik had zo'n idee dat ik niet de eerste was met deze wens) en ik kwam al gauw de oplossing met een Finder relais en KaKu-deurbelzender tegen. Helaas heeft deze oplossing een vrij pittig prijskaartje, het relais kost je 19 euro en de deurbelzender 14,99 euro. In mijn geval zou ik het dan ook nog x2 moeten doen omdat ik twee bellen heb. Dat zou wel heel erg duur (67,98 euro) worden voor zoiets basaals 8)7

Ik heb daarom gekeken of ik zelf wat kon solderen om dit te bereiken. Ik had nog een goedkope 433Mhz remote uit China liggen. Deze heeft een PT2262 chip en kan daardoor gebruikt worden met de RFXCOM transceiver. Ook heeft deze twee drukknoppen (A en B ) die beiden met een eigen ID in Domoticz binnenkomen. See where we're going to >:) ?

Eerst maar eens ťťn deurbel zien af te tappen. Ik ben gestart met die van de galerij aangezien dat een deurbel is die het meest lijkt op deurbellen in andere huizen. Ik heb eerst geprobeerd om met een optocoupler en weerstand het signaal af te tappen. Dit wou echter niet goed lukken, er gebeurde OF niks, OF de knopjes bleven constant 'ingedrukt'. Nog wat zitten prutsen met de weerstandswaarde, maar het lukte niet echt.

Daarom het idee met een optocoupler laten varen en wat aan het graven geweest in m'n onderdelenbak. Toen kwam ik twee printplaatjes met 12V relais tegen. Dit zou nog makkelijker zijn, het relais verbind de twee draadjes van de remote met elkaar en klaar.
Omdat de deurbel op wisselspanning werkt moest ik het nog even gelijkrichten. Dit gedaan met een diode. Om het signaal wat 'stabieler' te maken zodat het relais niet klappert heb ik nog een elco toegevoegd. Heb niet echt gelet op de waarden, gewoon wat spul gepakt wat ik nog had liggen.
Dit getest en bleek goed te werken voor de galerij-deurbel.

Daarna die van de intercom nog.
In de unit die in de gang hangt om terug te kunnen praten zit een zoemer, na even uitpluizen kwam ik erachter dat deze op 12V AC werkt. Dit scheelt aangezien ik een 12V relais had. Als de zoemer op 24V AC zou werken dan moest ik de schakeling verder aanpassen, nu kon ik hem gewoon 2x opbouwen.
Uiteindelijk kwam ik tot dit resultaat:
http://tweakers.net/ext/f/fk0P30SrT8KDTO9WwuTjEsgO/full.jpg

Het schema is als volgt:
http://tweakers.net/ext/f/Fly1GYzLyKkudd0dc6sTdgZL/full.png
Je sluit het spul parallel aan de huidige deurbel/zoemer aan. Eťn van de draden gaat rechtstreeks naar het relais, de andere gaat door de diode om de spanning te gelijkrichten. Over de spoel staat nog een elco.
De uitgang van het relais (NO, Normally Open) is aangesloten op de soldeerpads van een van de knoppen van de afstandsbediening.
Het type diode & elco komt niet nauwkeurig, ik had dit nog liggen.

Welke afstandsbediening je moet hebben is even kijken, je wilt eentje die door de RFXCOM kan worden opgepikt, zoals de PT2262 chip. Ik moest bij mijn afstandsbediening nog een weerstand (die de oscillatiefrequentie regelt geloof ik) vervangen, volgens mij was het 4.7MΩ en heb ik hem vervangen door een 3.3MΩ

Ik krijg nu voor elke keer dat de bel wordt ingedrukt een signaal binnen in Domoticz. Opzich doet de schakeling het dus prima, maar aangezien de pakketbezorgers e.d. er een handje van hebben om 3x aan te bellen is het nogal irritant om binnen een paar seconden meerdere meldingen te krijgen.
Ik heb daarom een Lua script gemaakt voor Domoticz, die kijkt hoe lang de laatste keer aanbellen geleden was. Als dat minder dan 30 seconden is dan zal het script niet nog een keer een melding sturen. Is het MEER dan 30 seconden geleden (de volgende beller :+ ) dan zal er wel weer een bericht gestuurd worden. Werkt perfect!

Als Domoticz het signaal ontvangt dan trapt deze een Lua-script af. Dit Lua-script start vervolgens een Bash script
Dit laatste script maakt een snapshot van de IP-camera die op de voordeur gericht is. Het script stuurt mij een Pushover bericht gestuurd op m'n smartphone en wordt de afbeelding als bijlage in een mailtje naar mij verzonden. Aan het einde van het script wordt nog gekeken of er in de lokale map nog oude snapshots staan, alles ouder dan ťťn week gooi ik weg, vind ik niet interessant om terug te kijken.
De werking van het script staat ook hier beschreven..

Uiteindelijk is dit het resultaat op m'n telefoon:
http://tweakers.net/ext/f/N8nxL2hZ5fEF5Bn5zPczT6Nf/full.png
Bij de deurbel aan de galerij krijg ik eenzelfde berichtje + een mailtje met fotootje.

Uiteindelijk ben ik voor nog geen 5 euro aan onderdelen klaar. Er zat nog een zwakke schakel in deze setup, de afstandsbediening werkt oorspronkelijk met een batterijtje (A23 12V-celletje). Er wordt niet heel vaak aangebeld, maar uiteindelijk gaat een batterij een keer leeg. Ik heb daarom een creatieve oplossing bedacht: de afstandsbediening werkt op 12V, net als m'n router! Ik heb daarom een Y-snoertje gemaakt waarmee ik 12V aftap van de voeding van m'n router en dat vervolgens weer doorlus naar de router en de afstandsbediening. Nu hoef ik mij dus geen zorgen meer te maken over het leeglopen van de batterij.

I love it when a plan comes together :Y)

Maandelijks pushbericht met meterstanden slimme meter

Door ThinkPad op maandag 3 augustus 2015 08:51 - Reacties (6)
CategorieŽn: Domotica, Energiebesparing, Views: 2.951

Ik lees mijn slimme meter (Kaifa MA105) uit met Domoticz, via een P1-kabel (RJ11 naar USB). Hiermee kan ik netjes m'n elektra en gasverbruik inzien via Domoticz.

Domoticz toont echter nergens de meterstanden (ja, intern in de database). Ik vind het toch wel fijn om die achter de hand te hebben. Mocht het gruwelijk uit de klauwen lopen en m'n Domoticz install helemaal kaput zijn dan heb ik iig nog de mogelijkheid om zelf m'n maandverbruik te kunnen berekenen a.d.h.v. de meterstanden.

Ik heb daarom een (Python) script gemaakt die mij op elke eerste dag van de maand om 0:01 (dus eigenlijk NET na de laatste dag van de vorige maand) een pushbericht (Pushover) stuurt met de meterstanden (elektra hoog, elektra laag & gas). Op die manier kan ik het zelf ook nog bijhouden in een Excel bestand of iets dergelijks.

Het bericht wat je krijgt ziet er zo uit:
http://tweakers.net/ext/f/qvKvhRr02CaKyZPhTEeumeqn/full.png

Het Python-script:

Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import sys
import json
import urllib2
import re
import time
import datetime
import httplib, urllib
 
def open_port():
    pass
 
def close_port():
    pass
 
class Domoticz():
 
    def __init__(self, url):
 
        self.baseurl = url
 
    def __execute__(self, url):
 
        req = urllib2.Request(url)
        return urllib2.urlopen(req, timeout=5)
 
    def get_device(self, xid):
        """
        Get the Domoticz device information.
        """
        url = "%s/json.htm?type=devices&rid=%s" % (self.baseurl, xid)
        data = json.load(self.__execute__(url))
        return data
 
 
def get_el_values(url, device_id):
    """
    Get electricity meter readings.
    """
 
    device_data = Domoticz(url).get_device(device_id)
    data = device_data['result'][0]['Data']
 
    ex = re.compile('^([0-9\.]+);([0-9\.]+);([0-9\.]+);([0-9\.]+);([0-9\.]+);([0-9\.]+)$')
 
    groups = ex.match(data).group
    meter_high = float(groups(1)) / 1000
    meter_low = float(groups(2)) / 1000
    #out_high = float(groups(3)) / 1000
    #out_low = float(groups(4)) / 1000
    #actual_in = float(groups(5)) / 1000
    #actual_out = float(groups(6)) / 1000
 
    return meter_high, meter_low#, out_high, out_low, actual_in, actual_out
 
def get_gas_values(url, device_id):
    """
    Get gasmeter reading.
    """
 
    device_data = Domoticz(url).get_device(device_id)
    data = device_data['result'][0]['Data']
 
    ex = re.compile('^([0-9\.]+)$')
 
    groups = ex.match(data).group
    gasstand = float(groups(1)) #/ 1000
 
    return gasstand
# example usage
 
domoticzurl = "http://localhost:8080"
domoticzdeviceid_el = 6
domoticzdeviceid_gas = 7
#ElectricityRateUsedPeak, ElectricityRateUsedOffPeak, ElectricityRateGeneratedPeak, ElectricityRateGeneratedOffPeak, ElectricityTotalUsed, ElectricityCurrentRateOut = get_el_values(domoticzurl, domoticzdeviceid_el)
ElectricityRateUsedOffPeak, ElectricityRateUsedPeak = get_el_values(domoticzurl, domoticzdeviceid_el)
GasMeterReading = get_gas_values(domoticzurl, domoticzdeviceid_gas)
 
#print "-- DOMOTICZ ENERGIE--"
#print "Meterstand piektarief (hoog):\t\t"+str(ElectricityRateUsedPeak)+"kWh"
#print "Meterstand daltarief (laag):\t\t"+str(ElectricityRateUsedOffPeak)+"kWh"
#print "Gasmeterstand:\t\t\t\t"+str(GasMeterReading)+"m3"
#print "Totaal:\t\t\t"+str(ElectricityRateUsedPeak + ElectricityRateUsedOffPeak)+"kWh"
#print ""
#print "- Teruggeleverd"
#print "Daltarief:\t\t"+str(ElectricityRateGeneratedOffPeak)+"kWh"
#print "Piektarief:\t\t"+str(ElectricityRateGeneratedPeak)+"kWh"
#print "Huidig verbruik:\t"+str(ElectricityTotalUsed)
 
conn = httplib.HTTPSConnection("api.pushover.net:443")
conn.request("POST", "/1/messages.json",
  urllib.urlencode({
    "token": "ABCD1234",
    "user": "ABCD1234",
    "message": "Meterstand elektra hoog: "+str(ElectricityRateUsedPeak)+"\n""Meterstand elektra laag: "+str(ElectricityRateUsedOffPeak)+"\n""Gasmeterstand: "+str(GasMeterReading)+"",
    "title": "Domoticz - meterstanden",
    "priority": "-1",
  }), { "Content-type": "application/x-www-form-urlencoded" })
conn.getresponse()


Verdere uitleg van het script kun je hier vinden: http://domoticz.com/wiki/Meter_readings_monthly
Volg de stappen en als het goed is zou je dan ook maandelijks een soortgelijk berichtje moeten krijgen.

Pushover is overigens niet gratis, je moet ťťnmalig betalen (ik meen §4) maar dat vind ik het geld wel waard. De service werkt supersnel (op de commandline op Enter drukken bij uitvoeren script en nog geen twee seconden later heb je het bericht al binnen). Desgewenst kun je het script ook ombouwen naar een andere service, het script roept via een simpele 'curl' de HTTP-API van Pushover aan. Voor Prowl (gratis te gebruiken op iOS dacht ik) heeft een medetweaker het script aangepast.

Uitlezen van de slimme meter P1-poort met een Arduino en waarden opslaan in MySQL-database

Door ThinkPad op dinsdag 19 augustus 2014 12:53 - Reacties (34)
CategorieŽn: Electronica, Energiebesparing, Views: 62.868

Zo, het is alweer een tijdje geleden dat ik een blogpost heb geschreven (vorige was in januari 2014 over het nut van een pompschakelaar voor je vloerverwarming. Energiebesparing much?)

Vandaag eentje over het uitlezen van een slimme energiemeter met een Arduino en het opslaan van de informatie in een MySQL-database.

Inhoudsopgave
Inleiding
Monitoren energieverbruik
Slimme meter
De oplossing
Arduino, PHP, MySQL-code
Hardware
Grafisch maken van de data
Gasverbruik uploaden naar Mindergas.nl
Todo list
Het eindresultaat

Inleiding
Ik ben de laatste tijd bezig geweest met het omlaag brengen van m'n energieverbruik. Toen ik samen met m'n vriendin in deze woning trok (nov. '13) heb ik gelijk overal LED-lampen ingedraaid en gezorgd dat de apparaten die veel energie gebruiken zoveel mogelijk A+ of beter zijn. Elektraverbruik is daarmee al best goed, we zitten op ~140 kWh per maand met z'n tweeŽn.

Gasverbruik heb ik ook zoveel mogelijk terug proberen te dringen, door gelijk toen ik hier kwam wonen de CV-ketel te tunen en de radiatoren waterzijdig inregelen.

Monitoren energieverbruik
Volgende stap was het monitoren van m'n energieverbruik, dit ging echter wat lastig. M'n woning (huurwoning uit 1988) beschikte nog over een ouderwetse draaischijf kWh-meter (1987) Deze viel nog wel uit te lezen door met een TCRT5000 IR-sensor te kijken wanneer de zwarte streep voorbij kwam. De gasmeter was echter zo oud (1987) dat deze 0,0 uitleesmogelijkheden had. Geen reflecterend vakje op het telwerk, geen magnetisch veld voor een reedcontact, NIKS.

Slimme meter
Daarom heb ik besloten om een slimme meter aan te vragen via prioriteitsplaatsing. Je betaalt dan §72,60 en dan wordt er een slimme elektra- en gasmeter bij je geplaatst.

Over de voor- en nadelen, privacy etc. van de slimme meter ga ik het hier niet hebben. Dat moet ieder voor zichzelf beslissen, en is genoeg informatie over te vinden op internet. Als je nu nog een oude draaischijfmeter hebt hangen en je hebt/wilt zonnepanelen dan kun je beter bij je huidige meter blijven omdat het salderen veel gunstiger is. Ik heb/wil geen zonnepanelen (want: huurflatje), en voor mij biedt de slimme meter een hoop mogelijkheden voor het nauwkeurig bijhouden van m'n energieverbruik.

Voordeel van de slimme meter is dat je je energieverbruik veel beter inzichtelijk kunt krijgen. De meter heeft namelijk een P1-poort waarover de meetgegevens via een seriŽle verbinding worden uitgestuurd. Deze poort kun je dan uitlezen met een commercieel product, of zelf iets bouwen. Mijn voorkeur ging uit naar het laatste. Ik ben niet vies van een beetje hobbyen, en een commerciŽle oplossing is vaak nogal aan de prijs (~§100).

Je kunt ook je slimme meter gratis op afstand laten uitlezen, bijvoorbeeld via Enelogic. Nadeel is echter dat je geen live verbruik hebt en je kunt pas een dag later het verbruik van afgelopen dag zien. Ook kun je niet zelf bij de data, een beetje lekker klooien met query's (hoe vaak zit m'n verbruik boven de XX watt, hoeveel kWh gebruik ik gemiddeld per dag?) is er dus niet bij.

De oplossing
Er zijn al een hoop hobbyisten die mij zijn voorgegaan hiermee. Vaak wordt er dan naar een Raspberry Pi gegrepen. Leuk, maar in mijn ogen redelijk overkill (een Raspberry draait een Linux omgeving, terwijl ik alleen wat waarden uit een serieel ontvangen bericht wil halen, wat ook prima met een Arduino kan). Ik wilde daarom graag iets bouwen met Arduino gezien de leuke prijs hiervan. Ik heb al een NAS (Synology DS114) draaien waar ook al een webserver + MySQL-database op draait. Een plek om de ontvangen data op te slaan was er dus al.

Voor een Arduino Duemilanove en een W5100 Ethernet shield was ik op eBay samen zo'n 18 euro kwijt. De helft van wat een Raspberry Pi kost :) Dan nog wat klein spul (RJ11 connector, stukje snoer, transistor) wat <3 euro heeft gekost.

Arduino code
Op basis van bestaande Arduino code heb ik een sketch gemaakt die de P1-poort van de slimme meter uitleest en de waarden in een MySQL-database op m'n NAS opslaat.

De basis was deze code. Die heb ik aangepast om tot onderstaande code te komen (met dank aan mede-tweakers die mij in m'n topic geholpen hebben!)


C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/* Arduino 'slimme meter' P1-port reader.
 
 This sketch reads data from a Dutch smart meter that is equipped with a P1-port.
 Connect 'RTS' from meter to Arduino pin 5
 Connect 'GND' from meter to Arduino GND
 Connect 'RxD' from meter to Arduino pin 0 (RX)
 
 Baudrate 115200, 8N1.
 BS170 transistor & 10k resistor is needed to make data readable if meter spits out inverted data
 
 A .php file is requested (with consumption numbers in the GET request) every minute (interval set at line #52)
 created by 'ThinkPad' @ Tweakers.net, september 2014
 
 http://gathering.tweakers.net/forum/list_messages/1601301
 */

#include <AltSoftSerial.h>
#include <SPI.h>
#include <Ethernet.h>
// AltSoftSerial always uses these pins:
//
// Board          Transmit  Receive   PWM Unusable
// -----          --------  -------   ------------
// Teensy 2.0         9        10       (none)
// Teensy++ 2.0      25         4       26, 27
// Arduino Uno        9         8         10
// Arduino Mega      46        48       44, 45
// Wiring-S           5         6          4
// Sanguino          13        14         12

byte mac[] = {
  0xDE, 0xAD, 0xBE, 0x30, 0x32, 0x31};
IPAddress ip(192,168,4,7);
IPAddress server(192,168,4,4);
EthernetClient client;

const int requestPin =  5;         
char input; // incoming serial data (byte)
bool readnextLine = false;
#define BUFSIZE 75
char buffer[BUFSIZE]; //Buffer for serial data to find \n .
int bufpos = 0;
long mEVLT = 0; //Meter reading Electrics - consumption low tariff
long mEVHT = 0; //Meter reading Electrics - consumption high tariff
long mEAV = 0;  //Meter reading Electrics - Actual consumption
long mG = 0;   //Meter reading Gas

long lastTime = 0;        // will store last time 
long interval = 60000;           // interval at which to blink (milliseconds)

void setup() {
  Serial.begin(115200);
  delay(1000);
  Ethernet.begin(mac, ip);
  delay(1000);
  pinMode(4, OUTPUT);                  // SD select pin
  digitalWrite(4, HIGH);               // Explicitly disable SD

  //Set RTS pin high, so smart meter will start sending telegrams
  pinMode(requestPin, OUTPUT);
  digitalWrite(requestPin, HIGH);
}

void loop() {

  decodeTelegram();

  if(millis() - lastTime > interval) {
    lastTime = millis();   
    //send data to PHP/MySQL
    httpRequest();
    //Reset variables to zero for next run
    mEVLT = 0;
    mEVHT = 0;
    mEAV = 0;
    mG = 0;
    //Stop Ethernet
    client.stop();
  }
} //Einde loop

void decodeTelegram() {
  long tl = 0;
  long tld =0;

  if (Serial.available()) {
    input = Serial.read();
    char inChar = (char)input;
    // Fill buffer up to and including a new line (\n)
    buffer[bufpos] = input&127;
    bufpos++;

    if (input == '\n') { // We received a new line (data up to \n)
      if (sscanf(buffer,"1-0:1.8.1(%ld.%ld" ,&tl, &tld)==2){
        tl *= 1000;
        tl += tld;
        mEVLT = tl;
      }

      // 1-0:1.8.2 = Elektra verbruik hoog tarief (DSMR v4.0)
      if (sscanf(buffer,"1-0:1.8.2(%ld.%ld" ,&tl, &tld)==2){
        tl *= 1000;
        tl += tld;
        mEVHT = tl;
      }

      // 1-0:1.7.0 = Electricity consumption actual usage (DSMR v4.0)
      if (sscanf(buffer,"1-0:1.7.0(%ld.%ld" ,&tl , &tld) == 2)
      { 
        mEAV = (tl*1000)+tld;
      }

      // 0-1:24.2.1 = Gas (DSMR v4.0) on Kaifa MA105 meter
      if (strncmp(buffer, "0-1:24.2.1", strlen("0-1:24.2.1")) == 0) {
        if (sscanf(strrchr(buffer, '(') + 1, "%d.%d", &tl, &tld) == 2) {
          mG = (tl*1000)+tld; 
        }
      }

      // Empty buffer again (whole array)
      for (int i=0; i<75; i++)
      { 
        buffer[i] = 0;
      }
      bufpos = 0;
    }
  } //Einde 'if AltSerial.available'
} //Einde 'decodeTelegram()' functie

void httpRequest() {
  // if there's a successful connection:
  if (client.connect(server, 80)) {
    client.print("GET /www/slimmemeter/p1.php?mEVLT=");
    client.print(mEVLT);
    client.print("&mEVHT=");
    client.print(mEVHT);
    client.print("&mEAV=");
    client.print(mEAV);
    client.print("&mG=");
    client.print(mG);
    client.println(" HTTP/1.1");
    client.println("Host: 192.168.4.4");
    client.println("User-Agent: arduino-ethernet");
    client.println("Connection: close");
    client.println();
    //Request complete; empty recieve buffer
    while (client.available()) { //data available
      char c = client.read(); //gets byte from ethernet buffer
    }
    client.println();
  } 
  else {
    client.stop();
  }
}


Pas indien gewenst het MAC-adres en IP-adres van de Arduino aan (regel 32 & 33). Ook wil je waarschijnlijk het IP-adres van het apparaat waar je MySQL op draait aanpassen (regel 34 & 142).

Het resultaat van bovenstaande sketch is dat er zodra een telegram binnenkomt bij de Arduino, hij de interessante waarden hieruit haalt en daarna elke minuut het PHP bestand op m'n NAS aanroept via een GET-request. In de URL staan de verbruikscijfers uit het P1-telegram.

Oorspronkelijk had ik de sketch zo gebouwd dat van elk telegram wat binnenkwam op de Arduino de waarden werden weggeschreven naar de database. De slimme meter spuugt echter iedere 10 sec. een nieuw telegram uit. Dit zorgt voor enorm veel data (8.640 rijen per dag, 3,15 miljoen per jaar!). Een interval van 1 minuut is ook prima, dat gebruiken veel commerciŽle uitleesoplossingen ook. Mocht je wel willen dat voor elk telegram (elke 10sec dus) de waarden worden weggeschreven, dan kun je de originele code nog terugvinden hier: http://pastebin.com/N7jHBTDu

Let er overigens op dat als je de code upload naar de Arduino, je de hardware van pin 0 loskoppelt. Anders gaan zaken conflicteren met elkaar. Na het uploaden van de sketch kun je het weer aansluiten. Ik heb zelf een 'shield' gemaakt d.m.v. gaatjesprint en header-pinnen. Het shield kan ik zo van de Arduino af trekken en na uploaden er weer op prikken.

Het PHP bestand bevat de volgende code:
p1.php

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<?php
error_reporting(E_ALL);

//Connect to database
$MyUsername = "p1logger";  // enter your username for mysql
$MyPassword = "p1logger";  // enter your password for mysql
$MyHostname = "localhost";      // this is usually "localhost" unless your database resides on a different server

$dbh = mysql_pconnect($MyHostname , $MyUsername, $MyPassword);
$selected = mysql_select_db("p1",$dbh);

//Waardes van vorige wegschrijf actie ophalen
$query = mysql_query("SELECT laag_tarief, hoog_tarief, huidig_verbruik, gas FROM `readings` ORDER BY `readings`.`time`  DESC LIMIT 1");
$row = mysql_fetch_array($query);
$previous_laag_tarief = $row[0];
$previous_hoog_tarief = $row[1];
$previous_huidig = $row[2];
$previous_gas = $row[3];
$min_vermogen = 0;
$max_vermogen = 230*25; //Maximale vermogen = 230V * vermogen hoofdzekering (1x25A)

//Alle opgehaalde variabelen op type 'INTEGER' zetten ivm vergelijken zometeen
settype($previous_elektra, "integer");
settype($previous_huidig, "integer");
settype($previous_gas, "integer");

//GET variabelen naar andere variabele schrijven
$mEVLT = $_GET["mEVLT"];
$mEVHT = $_GET["mEVHT"];
$mEAV = $_GET["mEAV"];
$mG = $_GET["mG"];

//GET variabelen op 'integer' zetten
settype($mEVLT, "integer");
settype($mEVHT, "integer");
settype($mEAV, "integer");
settype($mG, "integer");


//Checken of binnengekomen standen voldoen aan eisen (meterstand = hoger dan vorige, huidig verbruik > minimale vermogen, kleiner dan maximale vermogen) om incorrecte waarden te negeren
if (
    $mEVLT >= $previous_laag_tarief
    && $mEVHT >= $previous_hoog_tarief 
    && $mG >= $previous_gas //Inkomende meterstand moet groter zijn dan vorige meterstand
    && $mG <= ($mG + 6000) //Gasmeter is type 'G6', which stands for max. 6m3/hour. So value can never be bigger than value + 6000
    && $mEAV >= $min_vermogen //Huidig verbruik moet groter zijn dan minimale verbruik (nachtverbruik)
    && $mEAV <= $max_vermogen //Huidig verbruik moet kleiner zijn dan max. vermogen 1fase aansluiting
    ) 
{ 
    $SQL = "INSERT INTO p1.readings (id, time, laag_tarief, hoog_tarief, huidig_verbruik, gas) VALUES (NULL, NULL, '".$mEVLT."', '".$mEVHT."', '".$mEAV."', '".$mG."')";     
    mysql_query($SQL);
}
else { 

    //Foutieve waarden wegschrijven naar tabel voor latere debugging
    $SQL = "INSERT INTO p1.faulty_readings (id, time, laag_tarief, hoog_tarief, huidig_verbruik, gas) VALUES (NULL, NULL, '".$mEVLT."', '".$mEVHT."', '".$mEAV."', '".$mG."')";    
    mysql_query($SQL);
}


?>


Let niet op de PHP code, dit is erg ranzig bij elkaar gehackt. Het werkt voor mij i.i.g. wel. Het zorgt ervoor dat incorrecte waarden zoveel mogelijk worden genegeerd.
Heb je een beter idee dan hoor ik dat graag.

De database (p1) heeft ťťn tabel ('readings'), welke er als volgt uitziet:

code:
1
2
3
4
5
6
7
8
9
10
+-----------------+-----------+------+-----+-------------------+----------------+
| Field           | Type      | Null | Key | Default           | Extra          |
+-----------------+-----------+------+-----+-------------------+----------------+
| id              | int(11)   | NO   | PRI | NULL              | auto_increment |
| time            | timestamp | NO   |     | CURRENT_TIMESTAMP |                |
| laag_tarief     | int(11)   | NO   |     | NULL              |                |
| hoog_tarief     | int(11)   | NO   |     | NULL              |                |
| huidig_verbruik | int(4)    | NO   |     | NULL              |                |
| gas             | int(11)   | NO   |     | NULL              |                |
+-----------------+-----------+------+-----+-------------------+----------------+



Hardware

De hardware is niet heel moeilijk:
Je prikt het Ethernetshield op de Arduino en sluit een kabel vanaf de slimme meter op je Arduino aan.
De P1-poort van de slimme meter gebruikt eigenlijk gewoon een RJ11 telefoonconnector. Je kunt hiervoor eenvoudig zelf een kabel maken. De pinout vind je hier.

De kabel sluit je op de volgende manier op je Arduino aan:

code:
1
2
3
4
5
6
7
+--------------+---------+
| Slimme meter | Arduino |
+--------------+---------+
| RTS (2)      | D5      |
| GND (3)      | GND     |
| RxD (5)      | 0 (RX)  |
+--------------+---------+



Mijn meter (Kaifa MA105) spuugt de data echter geÔnverteerd uit, dus ik moest nog een oplossing maken met een transistor (BS170) en een 10kΩ weerstand. Ook spuugt mijn meter de data uit met 115200 baud i.p.v. 9600. Start/stop bits is 8N1 bij mijn meter. Als jouw meter 7N1 gebruikt zul je dat even weer in moeten bouwen a.d.h.v. de voorbeeldsketch waar ik bovenaan naar link.

Om de data weer terug te inverteren moet je een hardware oplossing maken. Dit kan zoals hierboven genoemd met een simpele transistor (BC547 of BS170) en een weerstand van 10kΩ (schema).

Grafisch maken van de data
Nu de Arduino aan het loggen is wil je natuurlijk ook zien wat je energieverbruik is. Een tabel vol met cijfertjes zegt je waarschijnlijk weinig. Ik heb voor mijzelf een opzetje gemaakt met Highcharts. Met Highcharts kun je vrij eenvoudig grafieken genereren. De grafieken zijn ook op mobiele devices vrij aardig te bekijken.

Ik heb verschillende grafieken:
  • Eentje voor een lijngrafiek van het verbruik (per minuut). Die kun je hier vinden
  • Eentje met staafdiagrammen van het verbruik (elektra & gas) van de huidige maand. Die kun je hier vinden. Deze pagina heeft nog een andere pagina nodig om de data op te halen, die pagina kun je hier vinden.
De code zal vast niet heel netjes zijn opgesteld (ik ben geen fulltime programmeur, puur hobby dit) maar voor mijn doeleinde werkt het prima. Ook is alleen het huidige elektraverbruik zichtbaar. Gasverbruik doe ik nog niks mee.

Gasverbruik uploaden naar Mindergas.nl
Ik hield voorheen altijd handmatig mijn gasverbruik bij via www.mindergas.nl . Mindergas heeft ook een API om meterstanden te uploaden. Nu met deze P1-uitleesmogelijkheid upload ik elke avond automatisch de meterstand naar Mindergas. De code hiervoor kun je vinden in dit topic: http://gathering.tweakers...message/42816734#42816734

Todo list
- Kijken of ik een watchdog kan implementeren. Hoewel de Arduino nu al meer dan drie maanden zonder storingen de gegevens logt, wil ik de sketch zo maken dat hij 24/7/365 kan loggen zonder menselijk ingrijpen. Automatisch resetten bij vastlopen zou dan handig zijn.

Ik ben dit nog aan het uitzoeken, discussie daarover loopt in het topic. Opmerkingen of verbeteringen mbt de Arduino code ook graag daar plaatsen. Reacties op de PHP/MySQL/grafiek mogen hier, dat staat los van de Arduino sketch.

Eindresultaat
http://tweakers.net/ext/f/AIQRc0zbKr4XlOCbQOPrCMRo/full.png

http://tweakers.net/ext/f/bFrCsu0yazzKHc8dgVKlZOk5/full.png

Disclaimer:
Ik ben niet verantwoordelijk voor schade aan je slimme meter, jezelf, je Arduino of andere zaken betrokken in dit project. Uitvoeren op eigen risico!


Een reactie als het goed werkt zou ik waarderen. Verwacht overigens geen hulp als je het niet aan de praat krijgt. Heb helaas geen tijd om inhoudelijke hulp te verlenen. Het is puur bedoeld als opstapje en om de mogelijkheden van een Arduino en wat PHP & MySQL & Highcharts aan te tonen.

Waarom een pompschakelaar op je vloerverwarming zin heeft

Door ThinkPad op vrijdag 24 januari 2014 10:37 - Reacties (24)
Categorie: Energiebesparing, Views: 58.858

Situatieschets
Mijn ouders hebben vloerverwarming in hun huis. Om het water rond te pompen door de leidingen in de vloer, zit er op het vloerverwarming (VV)-systeem een pomp. Ik kwam een tijdje terug op internet een site tegen over energie besparen. Hier stond dat VV-pompen vaak 24/7 draaien, ook bij mijn ouders was dat het geval.

Analyse
In de oude situatie draaide de pomp 24/7 @ 67W. Dat is goed voor 587 kWh per jaar, en kost dan §130 op jaarbasis (bij een prijs van §0,22/kWh), bijna §11 per maand.
Omdat de installatie bij mijn ouders maar uit 3 leidinglussen bestaat, bleek na enig onderzoek dat de pomp ook wel een stand lager kon. Dit omdat er dan nog steeds genoeg stroming was door de leidingen. Het verbruik is hierdoor al gezakt naar 53W. Dit bespaart al 27 euro op jaarbasis!
De pomp draaide echter nog steeds 24/7. Ik vroeg mij af: "Als de ketel geen warm water aanvoert, waarom is het dan nodig om de pomp het water te laten circuleren?". Een goed antwoord hierop kon ik eigenlijk niet bedenken, dus ging ik op zoek naar een manier om de pomp uit te zetten als de CV-ketel niet aan het stoken was.

Genomen maatregel
Oplossing hiervoor werd gevonden in een pompschakelaar (ECO Pump Switch HY-02). De pompschakelaar steek je in het stopcontact, de stekker van de pomp in de schakelaar en de bijgeleverde temperatuursensor klem je op de leiding die het warme water vanaf de ketel aan de VV-verdeler voedt (even voelen welke buis het warmste is als CV-ketel aanstaat). Wat de pompschakelaar doet is simpelgezegd:
IF aanvoerleiding >= '33 graden' THEN pomp = aan, ELSE pomp = uit
In de zomer staat de verwarming uit en de pomp dus ook. Je hebt dan kans dat de pomp vast komt te zitten door interne roestvorming. De vloerverwarming in de zomer helemaal uitzetten is hierdoor niet aan te raden. Om vastzitten te voorkomen zal bovengenoemde pompschakelaar de pomp eens in de 24h even laten draaien.
Inpluggen en nooit meer naar om hoeven te kijken dus, ideaal!

De sensor zit aan een vrij lang snoer, in ons geval staat de CV-ketel een verdieping hoger, maar konden we het snoer van de sensor door een opening in de vloer laten lopen. De sensor konden we hierdoor vlak onder de ketel op de leiding klemmen, zodat de pompschakelaar snel reageert.

Het aantal draaiuren van de pomp is nu lastiger te berekenen, maar als we ervan uitgaan dat de ketel tussen 6:00 - 22:00 gebruikt zal worden (dat is het klokprogramma wat in de kamerthermostaat zit) dan kom je op maximaal 16 draaiuren per dag.

Opgeleverde besparing
53W bij 16 uur per dag is op jaarbasis 310 kWh en kost dan §68,20. Het verbruik is dus bijna gehalveerd ten opzichte van de oude situatie waarin de pomp 24/7 stond te draaien!
En dit is dus een groffe berekening van 16 draaiuren op een dag. In werkelijkheid zal het veel minder zijn omdat de ketel immers niet 16 uur staat te draaien, als het huis immers warm is duurt het vaak wel een poosje voor de CV-ketel weer aanslaat. In de zomermaanden hoeft de CV-ketel niet te stoken en zou het dus zomaar kunnen zijn dat de pomp 3 maanden niet hoeft te draaien. Het daadwerkelijke verbruik van de pomp op jaarbasis is dus veel minder.

Al met al is de conclusie dat je een pompschakelaar binnen de kortste keren hebt terugverdiend!! (in ons geval een halfjaar). Als je pomp een hoger vermogen heeft is dit nog sneller, de besparing is dan immers groter.
En een tweede voordeel is dat het comfort er ook wat op vooruit gaat. Het warme water blijft nu in de vloer aanwezig nadat de ketel weer is uitgeschakeld. In de originele situatie (pomp 24/7 aan) werd het water constant rondgepompt waardoor de vloer sneller weer afkoelde dan nu het geval is.

Zelf een oplossing bouwen
Wat ook wel handig is om te weten, is dat sommige ketels zijn uitgerust met een connector waar je een tweede pomp op kan aansluiten. Je zou daar de pomp van de vloerverwarming mee kunnen laten schakelen. Op die manier draait hij alleen als de CV-ketel aan het stoken is. Onze ketel (Remeha Calenta) heeft dit helaas niet, je moet dan een extra module inbouwen. Die module is duurder dan deze pompschakelaar dus vandaar dat we hiervoor hebben gekozen. Ook is een pompschakelaar die op temperatuur werkt universeel, mocht er ooit een andere ketel komen dan hoeft er aan deze setup niks gewijzigd te worden. Kijk even in je handleiding van je ketel of jouw ketel de mogelijkheid heeft voor een externe pomp. Scheelt weer het aanschaffen van een pompschakelaar. Wel even opletten dat het relais in je ketel het pompvermogen aankan!

Isolatie
Bij ons is de VV-verdeler geplaatst in een koude garage, op de planning staat nog om de blootliggende leidingen te voorzien van buisisolatie. Op die manier kan er nog een paar % gas bespaard worden. Om de verdeler zit al wel een omkasting met dik isolatiemateriaal.
Het isoleren is inmiddels gebeurd.

Trek ook eens het schot van je berging o.i.d. open waar je VV-installatie zit en onderzoek hoe het bij jou thuis geregeld is!
d:)b d:)b d:)b