P1 uitlezen met Arduino

Contents

P1 Slimme meter uitlezen met de Arduino

Zoals jullie weten is een groot deel van Nederland al omgebouwd naar de slimme meter.

Wat jullie misschien nog niet bekend is, is dat deze meter een P1 aansluiting heeft. Deze aansluiting is er voor gemaakt om de meter uit te kunnen lezen. Er mogen van allerhande soort meters aan worden gehangen zoals Toon en Plugwise Smile P1. Deze meters kosten nog wel wat zodat ik er voor gekozen heb om een Arduino te gebruiken met een kabel die de gegevens uit leest.

Hiervoor het ik een NHduino Uno gebruikt. Je weet wel zo’n Chinese kloon van €3-4. Deze heeft zo zijn nadelen, maar ook zijn voordelen en er moet een aparte driver voor worden geladen om deze te kunnen gebruiken.

NHDuino Uno. De Chinese Arduino clone
NHDuino Uno. De Chinese Arduino clone

Als de driver is geinstalleerd, werkt dit net als de originele Arduino en kun je hem normaal gebruiken

Het telegram van de slimme meter op de P1 aansluiting

De P1 stuurt een zogenaamd telegram. Dit Telegram ziet er als volt uit:

 

Het telegram uit de slimme meter met uitleg
Het telegram uit de slimme meter met uitleg

Zoals te zien komt er dus heel wat informatie uit deze meter door middel van dit telegram.

Dit telegram is niet al te moeilijk op  de Serial-monitor van de Arduino te tonen. Dit kan met een sketch die overal op internet te vinden is. Een van de sketches zal ik hier laten zien. Deze werkt tenminste voor mijn slimme meter. Dit is de voor mij al complete sketch.

Aansluiting naar de p1 van de slimme meter en een Arduino

Voor het aansluiten van de P1 op de Arduino, heb ik gebruik gemaakt van het volgende schema

Aansluitschema Arduino en P1 slimme meter
Aansluitschema Arduino en P1 slimme meter

De weerstand is 10k ohm. De Bs170 heb ik vervangen voor een BC547. Dit werkt ook goed. Het is simpel aan te sluiten en het werkt naar behoren.

Sketches voor de Arduino (zender en ontvanger)

Doordat er gebruik wordt gemaakt van twee Arduino’s waarvan er 1 in de meterkast staat en 1 de master Arduino is die alles ontvangt, moeten er twee sketches worden gebruikt.

Er wordt hier GEEN gebruik gemaakt van een Ethernetshield omdat ik nog verschillende NRF24L01 printjes had liggen. Deze heb ik aan de Arduino gemonteerd door gebruik te maken van het volgende schema±

Aansluitschema Arduino en NRF24L01
Aansluitschema Arduino en NRF24L01

Doordat ik GEEN gebruik maak van teruglevering van mijn gewonnen vermogen van het zonnepaneel, wordt deze in de sketch ook niet gebruikt, maar daarvoor zou je hier terecht kunnen. Deze sketch maakt gebruik van een Ethernet-shield W5100 voor de Arduino.

 
 
 #include <AltSoftSerial.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.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

AltSoftSerial altSerial;

int msg[1];
RF24 radio(9,10);
const uint64_t pipe = 0xE8E8F0F0E1LL;

const int requestPin =  4;         
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 mEAT = 0;  //Meter reading Electrics - Actual generated electricity (Solar panels)
long mG = 0;   //Meter reading Gas
int tarief = 3; //Meter actual rate

void setup() {
  Serial.begin(115200);
  delay(1000);

  altSerial.begin(115200);
  delay(1000);

  radio.begin();
  radio.openWritingPipe(pipe);
}


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

  if (altSerial.available()) {
    input = altSerial.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)


      // 1-0:1.8.2 = Electricity consumption high tariff (DSMR v4.0)
      if (sscanf(buffer,"1-0:1.8.2(%ld%.%ld%*s" , &tl, &tld) >0 ) {
        tl *= 1000;
        tl += tld;
        mEVHT = tl;    
        //mEVHT = tl * 1000 + tld;
        if (mEVHT > 0) {

          //mEVHT = 0;
        }
      }

        if (sscanf(buffer,"0-0:96.14.0(%ld.%ld*s" , &tl) >0  )   //)
        {
          tarief = tl;
        }


      if (sscanf(buffer,"1-0:1.8.1(%ld.%ld" ,&tl, &tld)==2){
        tl *= 1000;
        tl += tld;
        mEVLT = tl;

        if (mEVLT > 0) {


        }
      }

      // 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;
        if (mEAV > 0) {

        }
      }

      // 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;

    }
     
    if (input == '!') {   //uitroepteken geeft einde van telegram aan, dus we gaan data versturen
      SendNrf();
      //printData();
      mEVHT=0;
      mEVLT = 0;
      mEAV = 0;
      mG = 0;
      tarief=3;
      //client.stop();
    } //Einde vraagteken detectie   

  } //Einde 'if AltSerial.available'

}

void SendNrf(){
  int i =0;
  String theMessage;
  //Building message to send my NRF24L01
  // use "\n\r" to make newline and return
  theMessage="\n\r.....Nieuw telegram.....";
  theMessage+="\n\rVerbruik hoog (Wh): ";
  theMessage+=mEVHT;
//  theMessage+="| ";
  theMessage+="\n\rVerbruik laag (Wh): ";
  theMessage+=mEVLT;
//  theMessage+="| ";  
  theMessage+="\n\rActueel verbruik (W): ";
  theMessage+=mEAV;
//  theMessage+="| ";  
  theMessage+="\n\rVerbruik gas (liters): ";
  theMessage+=mG;
//  theMessage+="| ";  
  theMessage+="\n\rHuidige tarief: ";
  if (tarief==1){
    theMessage+="dal\n\r";
  }
  else {
    theMessage+="hoog\n\r";
  }
  
  int messageSize = theMessage.length();
  for (int i = 0; i < messageSize; i++) {
    int charToSend[1];
    charToSend[0] = theMessage.charAt(i);
    radio.write(charToSend,1);
  }  
//send the 'terminate string' value...  
  msg[0] = 2; 
  radio.write(msg,1);
/*delay sending for a short period of time.  radio.powerDown()/radio.powerupp
//with a delay in between have worked well for this purpose(just using delay seems to
//interrupt the transmission start). However, this method could still be improved
as I still get the first character 'cut-off' sometimes. I have a 'checksum' function
on the receiver to verify the message was successfully sent.
*/
  radio.powerDown(); 
  delay(20000);
  radio.powerUp();
  
}

void printData(){
  Serial.println("********* BEGIN LOOP *********");  
  Serial.print("Elektra - meterstand verbruik HOOG tarief (Wh): ");
  Serial.println(mEVHT);  
  Serial.print("Elektra - meterstand verbruik LAAG tarief (Wh): ");
  Serial.println(mEVLT);  
  Serial.print("Elektra - actueel verbruik (W): ");
  Serial.println(mEAV);
  Serial.print("Gas - meterstand (liters): ");
  Serial.println(mG);

  Serial.print("Huidige tarief: ");
  if (tarief==1){
    Serial.println ("dal");
  }
  else {
    Serial.println("hoog");
  }
//  Serial.println(tarief);
  Serial.println("");
}
 

Okee het ziet er niet helemaal lekker uit, maar het is ook een sketch die is samen geraapt uit verschillende sketches die ik op internet heb gevonden.

Zoals te zien is, wordt de data geformatteerd en wel verzonden naar een andere Arduino

void SendNrf(){
  int i =0;
  String theMessage;
  //Building message to send my NRF24L01
  // use "\n\r" to make newline and return
  theMessage="\n\r.....Nieuw telegram.....";
  theMessage+="\n\rVerbruik hoog (Wh): ";
  theMessage+=mEVHT;
//  theMessage+="| ";
  theMessage+="\n\rVerbruik laag (Wh): ";
  theMessage+=mEVLT;
//  theMessage+="| ";  
  theMessage+="\n\rActueel verbruik (W): ";
  theMessage+=mEAV;
//  theMessage+="| ";  
  theMessage+="\n\rVerbruik gas (liters): ";
  theMessage+=mG;
//  theMessage+="| ";  
  theMessage+="\n\rHuidige tarief: ";
  if (tarief==1){
    theMessage+="dal\n\r";
  }
  else {
    theMessage+="hoog\n\r";
  }
  
  int messageSize = theMessage.length();
  for (int i = 0; i < messageSize; i++) {
    int charToSend[1];
    charToSend[0] = theMessage.charAt(i);
    radio.write(charToSend,1);
  }  
//send the 'terminate string' value...  
  msg[0] = 2; 
  radio.write(msg,1);
/*delay sending for a short period of time.  radio.powerDown()/radio.powerupp
//with a delay in between have worked well for this purpose(just using delay seems to
//interrupt the transmission start). However, this method could still be improved
as I still get the first character 'cut-off' sometimes. I have a 'checksum' function
on the receiver to verify the message was successfully sent.
*/
  radio.powerDown(); 
  delay(20000);
  radio.powerUp();
  
}

Dit is het zendgedeelte van de NRF2L01. Een andere Arduino ontvangt alle gegevens:

.....Nieuw telegram.....
Verbruik hoog (Wh): 613000
Verbruik laag (Wh): 584525
Actueel verbruik (W): 0
Verbruik gas (liters): 153144
Huidige tarief: dal


.....Nieuw telegram.....
Verbruik hoog (Wh): 613000
Verbruik laag (Wh): 584529
Actueel verbruik (W): 455
Verbruik gas (liters): 0
Huidige tarief: dal


.....Nieuw telegram.....
Verbruik hoog (Wh): 0
Verbruik laag (Wh): 584532
Actueel verbruik (W): 462
Verbruik gas (liters): 153144
Huidige tarief: dal

Zoals te zien is, wordt deze data redelijk goed over gestuurd. Dit gaat door muren heen langs computers en andere electromagnetische bronnen. Dit valt met totaal niet tegen. Vanaf de meterkast naar het uitleesstation praat ik rechtstreeks over een meter of 5.

Dat er nog af en toe bij de standen een 0 voor komt, moet er nog uit worden gefilterd. Dat is iets wat dus nog moet gebeuren.

De sketch die ik hiervoor gebruik is als volgt:

#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
#include <SPI.h>

/*
This sketch receives strings from sending unit via nrf24 
and prints them out via serial.  The sketch waits until
it receives a specific value (2 in this case), then it 
prints the complete message and clears the message buffer.
*/

int msg[1];
RF24 radio(9,10);
const uint64_t pipe = 0xE8E8F0F0E1LL;
int lastmsg = 1;
String theMessage = "";
void setup(void){
  Serial.begin(9600);
  radio.begin();
  radio.openReadingPipe(1,pipe);
  radio.startListening();
}
void loop(void){
  if (radio.available()){
    bool done = false;  
      done = radio.read(msg, 1); 
      char theChar = msg[0];
      if (msg[0] != 2){
        theMessage.concat(theChar);
        }
      else {
       Serial.println(theMessage);
       theMessage= ""; 
      }
   }
}

Tot nu toe worden deze gegevens alleen nog maar op het scherm getoond, maar ik moet hier nog aanpassingen aan maken om deze data in een database te pompen. Het is leuk als ze geformatteerd aan komen, maar er komt een centrale pc te hangen in de kamer die gebruik maakt van een database.

Deze database wordt gevuld door een Arduino die al de gegevens gaat ontvangen en verwerken.

infopagina op het scherm in de woonkamer
infopagina op het scherm in de woonkamer

Helaas staat alles nog niet op dit scherm, maar dat komt nog wel.

Dit zullen in elk geval de volgende gegevens zijn:

  1. accuspanning op bepaalde tijd
  2. zonnebak temperatuur op bepaalde tijd
  3. gegevens uit de slimme meter
  4. van elke ruimte de verlichting
  5. van elke ruimte de temperatuur
  6. Zwembad gegevens

Accuspanning op bepaalde tijd

Met deze gegevens wil ik in kaart brengen hoe mijn accuspanning verloopt. Ik wil hiervoor een grafiek gaan gebruiken. Deze data wordt door middel van de database bewaard tot volgende jaren om dan eventueel ook nog een verloop in de jaren te kunnen tonen.

zonnebak temperatuur op bepaalde tijd

De arduino schakelt te zonnebak aan  als de temperatuur boven de 36 graden komt. Dat is voldoende om er voor te kunnen zorgen, dat er met het verlies door de pijpen meegerekend er nog warme lucht het huis in wordt geblazen.

gegevens uit de slimme meter

Deze gegevens zullen ook in de database worden opgeslagen om zo ook het verbruik in kaart te kunnen brengen. Op het scherm zal ook worden getoond of we in een hoog of dal tarief zitten.

 

van elke ruimte de verlichting en van elke ruimte de temperatuur

Ik heb nog kleine kinderen en die willen wel eens vergeten om een lamp uit te doen. Dit wil ik beneden wel kunnen zien (om de stroomkosten te kunnen drukken). Ook komt er waarschijnlijk nog een touch deel op het scherm om er voor te zorgen, dat ik vanuit de woonkamer de lampen uit kan zetten.

Zwembad gegevens

De gegevens van het zwembad zullen in dit veld worden getoond. Ook hier kan door middel van het touch-deel de pomp aan en uit worden gezet.

 

Zoals jullie zien, is dit nogal een omvangrijk project. Maar wel leuk om te doen.

Ik laat jullie nog wel meer weten over dit project.

Mocht je op de hoogte willen worden gehouden, abonneer je dan hieronder op mijn mailinglijst


 

 

3 gedachten over “P1 uitlezen met Arduino”

  1. Hallo,
    ik wil ook graag mijn slimme meter uitlezen via p1 en arduino uno.

    ik wil eerst simpel beginnen en vond een mooi voorbeeld op uw site.
    ik heb de situatie gemaakt met bc547 en 10k OHM weerstand. dus aangesloten op mijn UNO.

    heeft u ook de sketch voor deze opstelling? ik sluit hem dus rechtstreeks op de pc aan.

    ik heb al een en ander geprobeerd maar krijg geen gegevens.
    ik hoor graag van u en hoop dat u mij wil en kunt helpen

Geef een reactie

Je e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *

Deze site gebruikt Akismet om spam te verminderen. Bekijk hoe je reactie-gegevens worden verwerkt.