Skip to content

Instantly share code, notes, and snippets.

@kenci
Last active November 22, 2015 19:03
Show Gist options
  • Select an option

  • Save kenci/2c024b6b7244e07fee64 to your computer and use it in GitHub Desktop.

Select an option

Save kenci/2c024b6b7244e07fee64 to your computer and use it in GitHub Desktop.
Pulse decoder for S0 Interface
//
// Produce a formatted string in a buffer corresponding to the value provided.
// If the 'width' parameter is non-zero, the value will be padded with leading
// zeroes to achieve the specified width. The number of characters added to
// the buffer (not including the null termination) is returned.
//
unsigned
fmtUnsigned(unsigned long val, char *buf, unsigned bufLen, byte width)
{
if (!buf || !bufLen)
return(0);
// produce the digit string (backwards in the digit buffer)
char dbuf[10];
unsigned idx = 0;
while (idx < sizeof(dbuf))
{
dbuf[idx++] = (val % 10) + '0';
if ((val /= 10) == 0)
break;
}
// copy the optional leading zeroes and digits to the target buffer
unsigned len = 0;
byte padding = (width > idx) ? width - idx : 0;
char c = '0';
while ((--bufLen > 0) && (idx || padding))
{
if (padding)
padding--;
else
c = dbuf[--idx];
*buf++ = c;
len++;
}
// add the null termination
*buf = '\0';
return(len);
}
//
// Format a floating point value with number of decimal places.
// The 'precision' parameter is a number from 0 to 6 indicating the desired decimal places.
// The 'buf' parameter points to a buffer to receive the formatted string. This must be
// sufficiently large to contain the resulting string. The buffer's length may be
// optionally specified. If it is given, the maximum length of the generated string
// will be one less than the specified value.
//
// example: fmtDouble(3.1415, 2, buf); // produces 3.14 (two decimal places)
//
void
fmtDouble(double val, byte precision, char *buf, unsigned bufLen)
{
if (!buf || !bufLen)
return;
// limit the precision to the maximum allowed value
const byte maxPrecision = 6;
if (precision > maxPrecision)
precision = maxPrecision;
if (--bufLen > 0)
{
// check for a negative value
if (val < 0.0)
{
val = -val;
*buf = '-';
bufLen--;
}
// compute the rounding factor and fractional multiplier
double roundingFactor = 0.5;
unsigned long mult = 1;
for (byte i = 0; i < precision; i++)
{
roundingFactor /= 10.0;
mult *= 10;
}
if (bufLen > 0)
{
// apply the rounding factor
val += roundingFactor;
// add the integral portion to the buffer
unsigned len = fmtUnsigned((unsigned long)val, buf, bufLen);
buf += len;
bufLen -= len;
}
// handle the fractional portion
if ((precision > 0) && (bufLen > 0))
{
*buf++ = '.';
if (--bufLen > 0)
buf += fmtUnsigned((unsigned long)((val - (unsigned long)val) * mult), buf, bufLen, precision);
}
}
// null-terminate the string
*buf = '\0';
}
//-----------------------------------------------------------------------------------------------
// JSON functions
//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
// JSON structure characters
//-----------------------------------------------------------------------------------------------
//JSON structure uses " = 34
char jsonS[] = {'{',34,'\0'}; //JSON start characters
char jsonB1[] = {34,':',34,'\0'}; //JSON characters between key and value
char jsonB2[] = {34,',',34,'\0'}; //JSON characters between each data pair
char jsonE[] = {34,'}','\0'}; //JSON end characters
//-----------------------------------------------------------------------------------------------
// Adds start of JSON characters
//-----------------------------------------------------------------------------------------------
char * srtJSON ( char * destination )
{
strcat(destination,jsonS);
}
//-----------------------------------------------------------------------------------------------
// Adds a JSON key and data pair to the string
//-----------------------------------------------------------------------------------------------
char * addJSON ( char * destination, const char * source, const double value )
{
strcat(destination,source);
strcat(destination,jsonB1);
char buf[20]; fmtDouble(value,3,buf);
strcat(destination,buf);
strcat(destination,jsonB2);
}
//-----------------------------------------------------------------------------------------------
// Adds end of JSON characters
//-----------------------------------------------------------------------------------------------
char * endJSON ( char * destination )
{
str[strlen(destination)-3]='\0';
strcat(destination,jsonE);
}
//---------------------------------------------------------------------
// Pulse String Decoder
// GNU GPL openenergymonitor.org
// Author: Trystan Lea
//---------------------------------------------------------------------
unsigned long times[12]; //Array holds incoming pulse times
unsigned long count[12]; //Array holds incoming pulse count
int ti,ci; //times and counts index
int iStr = 0; //inString index
char inString[14]; //String for fetching each number
//---------------------------------------------------------------------
// Pulse String Decoder method
//
//String looks like this 2100:5,3200:4 = timeA,countA,timeB,countB
//Decode pulse string splits the string up and identifies if number is a time or a count
//---------------------------------------------------------------------
void decode_pulse_string()
{
if (Serial.available())
{
char inChar = Serial.read(); //Read in serial characters
if (inChar == ',' || inChar == ':' || inChar == '\n') //if any of the characters that define end of a number
{
inString[iStr] = '\0'; //end the string
long value = atol(inString); //convert the string to a long
if (inChar == ':') {times[ti] = value; ti++;} //Every value before : is a time
if (inChar == ',' || inChar == '\n') {count[ci] += value; ci++;} //Every value before , is a count
iStr=0; //reset inString index ready for the next argument
if (inChar == '\n') {ti = 0; ci = 0;} //Reset count and times index ready for the next line
}
else
{
inString[iStr] = inChar; //Add another character to the string
iStr++;
}
}
}
double getPower(int pin, double kwh_per_pulse) //Return power
{
return (3600000.0 * 1000 * kwh_per_pulse) / times[pin] * 1000;
}
double getkWhInc(int pin, double kwh_per_pulse)
{
double kwhInc = (count[pin]*kwh_per_pulse) * 1000; //Return Energy
return kwhInc;
}
void resetkWhInc(int pin)
{
count[pin]=0;
}
//---------------------------------------------------------------------
// Pulse String Decoder Sketch with Ethernet forwarding
// GNU GPL openenergymonitor.org
// Author: Trystan Lea
// Modified: kenci
// Added DSB1820 Sensors
//---------------------------------------------------------------------
#include <Ethernet.h>
#include <SPI.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS_PIN 2
OneWire oneWire(ONE_WIRE_BUS_PIN);
DallasTemperature sensors(&oneWire);
DeviceAddress vorlauf = { 0x28, 0x35, 0x9F, 0xC4, 0x06, 0x00, 0x00, 0x26 };
DeviceAddress rucklauf = { 0x28, 0xD9, 0x01, 0xDE, 0x06, 0x00, 0x00, 0x44 };
DeviceAddress warmwasser = { 0x28, 0x48, 0xE5, 0xC4, 0x06, 0x00, 0x00, 0x24 };
double temp_warmwasser, temp_vorlauf, temp_rucklauf;
byte mac[] = {0x54,0x55,0x53,0x10,0x04,0x28};
char server[] = "home.keno.lan";
IPAddress ip(192,168,1,177);
#define port 80
EthernetClient client;
char str[320]; //Increase this if not all of your json string is being sent.
unsigned long utimeT;
unsigned long utimeW; //Update time
//Float to string functions, see attached: ftoa
//thanks to Don Kinzer arduino forums
void fmtDouble(double val, byte precision, char *buf, unsigned bufLen = 0xffff);
unsigned fmtUnsigned(unsigned long val, char *buf, unsigned bufLen = 0xffff, byte width = 0);
void setup()
{
Serial.begin(115200); //Needs to be 115200 for fast transfer between pulse counting arduino and this arduino
// start the Ethernet connection:
if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP");
// no point in carrying on, so do nothing forevermore:
// try to congifure using IP address instead of DHCP:
Ethernet.begin(mac, ip);
}
// Initialize the Temperature measurement library
sensors.begin();
// set the resolution to 10 bit (Can be 9 to 12 bits .. lower is faster)
sensors.setResolution(vorlauf, 10);
sensors.setResolution(rucklauf, 10);
sensors.setResolution(warmwasser, 10);
// give the Ethernet shield a second to initialize:
delay(1000);
Serial.println("connecting...");
}
void loop()
{
decode_pulse_string(); //Method decodes string send from pulse counting arduino
if(millis()-utimeT>300000) {
utimeT = millis();
// Command all devices on bus to read temperature
sensors.requestTemperatures();
temp_warmwasser = printTemperature(warmwasser);
temp_vorlauf = printTemperature(vorlauf);
temp_rucklauf = printTemperature(rucklauf);
if(temp_vorlauf || temp_rucklauf || temp_warmwasser)
{
strcpy(str,""); //URL
srtJSON(str); //Start JSON
if(temp_vorlauf) addJSON(str,"temp_warmwaser",temp_warmwasser); //JSON line 1
if(temp_vorlauf) addJSON(str,"temp_vorlauf",temp_vorlauf); //JSON line 2
if(temp_rucklauf) addJSON(str,"temp_rucklauf",temp_rucklauf); //JSON line 3
endJSON(str); //End JSON
if (client.connect(server, port)) {
Serial.println("connected");
Serial.println("sending: /emoncms/api/post.json?apikey=xxxxxxxxxxxxxxxxxxxxxxxxxxx&node=41&json=");
Serial.print(str);
client.print("GET /emoncms/api/post.json?apikey=xxxxxxxxxxxxxxxxxxxxxxxxxxx&node=41&json="); //Add in your postin url here, there's more info on the web side of things in data modules and builds on the website
client.println(str); //Send the string
client.stop();
}
}
}
if (millis()-utimeW>10000)
{
//Serial.println("Alle 10 Sekunden");
utimeW = millis();
//-------------------------------------------------------------------------------------------
// 3) Create a string to be sent to the server
//-------------------------------------------------------------------------------------------
strcpy(str,""); //URL
srtJSON(str); //Start JSON
addJSON(str,"P0_power",getPower(0, 0.0005)); //JSON line 1
//addJSON(str,"P0_kwh", getkWhInc(0, 0.0005)); //JSON line 2
addJSON(str,"P1_power",getPower(1, 0.001)); //JSON line 1
//addJSON(str,"P1_kwh", getkWhInc(1, 0.001)); //JSON line 2
addJSON(str,"P2_power",getPower(2, 0.0005)); //JSON line 1
//addJSON(str,"P2_kwh", getkWhInc(2, 0.0005)); //JSON line 2
addJSON(str,"P3_power",getPower(3, 0.0005)); //JSON line 1
//addJSON(str,"P3_kwh", getkWhInc(3, 0.0005)); //JSON line 2
addJSON(str,"P4_power",getPower(4, 0.0005)); //JSON line 1
//addJSON(str,"P4_kwh", getkWhInc(4, 0.0005)); //JSON line 2
addJSON(str,"P5_power",getPower(5, 0.0005)); //JSON line 1
//addJSON(str,"P5_kwh", getkWhInc(5, 0.0005)); //JSON line 2
addJSON(str,"P6_power",getPower(6, 0.001)); //JSON line 1
//addJSON(str,"P6_kwh", getkWhInc(6, 0.001)); //JSON line 2
/*
addJSON(str,"P7_power",getPower(7, 0.005)); //JSON line 1
addJSON(str,"P7_kwh", getkWhInc(7, 0.005)); //JSON line 2
addJSON(str,"P8_power",getPower(8, 0.005)); //JSON line 1
addJSON(str,"P8_kwh", getkWhInc(8, 0.005)); //JSON line 2
addJSON(str,"P9_power",getPower(9, 0.005)); //JSON line 1
addJSON(str,"P9_kwh", getkWhInc(9, 0.005)); //JSON line 2
addJSON(str,"P10_power",getPower(10, 0.005)); //JSON line 1
addJSON(str,"P10_kwh", getkWhInc(10, 0.005)); //JSON line 2*/
//and so on...
//watch going out of range on the json string it has 150 characters, increase it in setup if you need to
endJSON(str); //End JSON
//-------------------------------------------------------------------------------------------
// 4) Send the string to the server
//-------------------------------------------------------------------------------------------
if (client.connect(server, port)) {
Serial.println("connected");
Serial.println("sending: /emoncms/api/post.json?apikey=xxxxxxxxxxxxxxxxxxxxxxx&node=51&json=");
Serial.print(str);
client.print("GET /emoncms/api/post.json?apikey=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&node=51&json="); //Add in your postin url here, there's more info on the web side of things in data modules and builds on the website
client.println(str); //Send the string
client.stop();
resetkWhInc(0);
resetkWhInc(1);
resetkWhInc(2);
resetkWhInc(3);
resetkWhInc(4);
resetkWhInc(5);
resetkWhInc(6);
/*resetkWhInc(7);
resetkWhInc(8);
resetkWhInc(9);
resetkWhInc(10);
*/
} else {
Serial.println("connection failed");
}
}
}
/*-----( Declare User-written Functions )-----*/
float printTemperature(DeviceAddress deviceAddress)
{
float tempC = sensors.getTempC(deviceAddress);
if (tempC == -127.00)
{
return 0;
}
else
{
return tempC;
}
}
//---------------------------------------------------------------------
// Pulse String Decoder Sketch with Ethernet forwarding
// GNU GPL openenergymonitor.org
// Author: Trystan Lea
//---------------------------------------------------------------------
#include <Ethernet.h>
#include <SPI.h>
byte mac[] = {0x54,0x55,0x53,0x10,0x04,0x28};
char server[] = "home.keno.lan";
IPAddress ip(192,168,1,177);
#define port 80
EthernetClient client;
char str[320]; //Increase this if not all of your json string is being sent.
unsigned long utime; //Update time
//Float to string functions, see attached: ftoa
//thanks to Don Kinzer arduino forums
void fmtDouble(double val, byte precision, char *buf, unsigned bufLen = 0xffff);
unsigned fmtUnsigned(unsigned long val, char *buf, unsigned bufLen = 0xffff, byte width = 0);
void setup()
{
Serial.begin(115200); //Needs to be 115200 for fast transfer between pulse counting arduino and this arduino
// start the Ethernet connection:
if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP");
// no point in carrying on, so do nothing forevermore:
// try to congifure using IP address instead of DHCP:
Ethernet.begin(mac, ip);
}
// give the Ethernet shield a second to initialize:
delay(1000);
Serial.println("connecting...");
}
void loop()
{
decode_pulse_string(); //Method decodes string send from pulse counting arduino
if (millis()-utime>10000)
{
utime = millis();
//-------------------------------------------------------------------------------------------
// 3) Create a string to be sent to the server
//-------------------------------------------------------------------------------------------
strcpy(str,""); //URL
srtJSON(str); //Start JSON
addJSON(str,"P0_power",getPower(0, 0.0005)); //JSON line 1
addJSON(str,"P0_kwh", getkWhInc(0, 0.0005)); //JSON line 2
addJSON(str,"P1_power",getPower(1, 0.001)); //JSON line 1
addJSON(str,"P1_kwh", getkWhInc(1, 0.001)); //JSON line 2
addJSON(str,"P2_power",getPower(2, 0.0005)); //JSON line 1
addJSON(str,"P2_kwh", getkWhInc(2, 0.0005)); //JSON line 2
addJSON(str,"P3_power",getPower(3, 0.0005)); //JSON line 1
addJSON(str,"P3_kwh", getkWhInc(3, 0.0005)); //JSON line 2
addJSON(str,"P4_power",getPower(4, 0.0005)); //JSON line 1
addJSON(str,"P4_kwh", getkWhInc(4, 0.0005)); //JSON line 2
addJSON(str,"P5_power",getPower(5, 0.0005)); //JSON line 1
addJSON(str,"P5_kwh", getkWhInc(5, 0.0005)); //JSON line 2
addJSON(str,"P6_power",getPower(6, 0.001)); //JSON line 1
addJSON(str,"P6_kwh", getkWhInc(6, 0.001)); //JSON line 2
/*
addJSON(str,"P7_power",getPower(7, 0.005)); //JSON line 1
addJSON(str,"P7_kwh", getkWhInc(7, 0.005)); //JSON line 2
addJSON(str,"P8_power",getPower(8, 0.005)); //JSON line 1
addJSON(str,"P8_kwh", getkWhInc(8, 0.005)); //JSON line 2
addJSON(str,"P9_power",getPower(9, 0.005)); //JSON line 1
addJSON(str,"P9_kwh", getkWhInc(9, 0.005)); //JSON line 2
addJSON(str,"P10_power",getPower(10, 0.005)); //JSON line 1
addJSON(str,"P10_kwh", getkWhInc(10, 0.005)); //JSON line 2*/
//and so on...
//watch going out of range on the json string it has 150 characters, increase it in setup if you need to
endJSON(str); //End JSON
//-------------------------------------------------------------------------------------------
// 4) Send the string to the server
//-------------------------------------------------------------------------------------------
if (client.connect(server, port)) {
Serial.println("connected");
Serial.println("sending: /emoncms/api/post.json?apikey=xxxxxxxxxxxxxxxxxxxxxxxxx&node=51&json=");
Serial.print(str);
client.print("GET /emoncms/api/post.json?apikey=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&node=51&json="); //Add in your postin url here, there's more info on the web side of things in data modules and builds on the website
client.println(str); //Send the string
client.stop();
resetkWhInc(0);
resetkWhInc(1);
resetkWhInc(2);
resetkWhInc(3);
resetkWhInc(4);
resetkWhInc(5);
resetkWhInc(6);
/*resetkWhInc(7);
resetkWhInc(8);
resetkWhInc(9);
resetkWhInc(10);
*/
} else {
Serial.println("connection failed");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment