Using the Flexs Q3 with emonCMS from the Open Energy Monitor project
emonCMS offers the user with a beautiful way to visualize energy usage and metrics by allowing the user to create custom dashboards by simply dragging widgets around and telling them what metric to display or graph.
Were going to use the UDP Streaming on the Flexs Q3 to stream data to a small listner application that will convert the received datagram into a json string and query the emoncms server with wget to push the data.
Start by configuring the device to stream to the IP of your server, copying your EMONCMS Read/Write key into the UID field and setting a send interval. Upload the Settings (Copy’s them to the RAM of the Flexs Device) and Apply them (Write the settings to the Non Volatile Memory and Reboots the device)
Now that we’ve got data streaming over the internet to our emoncms server we’ll compile our listener application. **This guide assumes that your operating on the Linux Operating System and have a basic build environment set-up.
Create a local file on your computer titled ‘main.c’
Clip and paste the below code into you ‘main.c’ file
Update the SERVER #define to reflect your emoncms server url
Compile the code with the command ‘gcc ./main.c’
Run the compiled application with the command ‘./a.out’
Bam! You should see your data showing up under the Feeds from your EmonCMS page.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include “config.h”
#define BUFSIZE sizeof(registers)
#define PORT 8000
#define SERVER “wget -q \’http://mydomain.ca/emoncms/input/post.json?node=%d&json={“
char *names[] = {
“Undefined”,
“Analog Ch 1”,
“Analog Ch 2”,
“Analog Ch 3”,
“Analog Ch 4”,
“Analog Ch 5”,
“Analog Ch 6”,
“Analog Ch 7”,
“Analog Ch 8”,
“Phase A Vrms”,
“Phase B Vrms”,
“Phase C Vrms”,
“Phase Aux Vrms”,
“Phase A Lrms”,
“Phase B Lrms”,
“Phase C Lrms”,
“Phase Aux Lrms”,
“Phase A PF”,
“Phase B PF”,
“Phase C PF”,
“Phase Aux PF”,
“Phase A Real Power”,
“Phase B Real Power”,
“Phase C Real Power”,
“Phase Aux Real Power”,
“Frequency”,
“Freq Rate of Change”,
“Output Ch 1”,
“Output Ch 2”,
“Output Ch 3”,
“Output Ch 4”,
“Output Ch 5”,
“Output Ch 6”,
“Output Ch 7”,
“Output Ch 8”,
“Header 1 GPIO”,
“Header 2 GPIO”,
“Header 3 GPIO”,
“Header 4 GPIO”,
“Header 5 GPIO”,
“Header 6 GPIO”,
“Header 7 GPIO”,
“Header 8 GPIO”,
“Time Second”,
“Time, Minute”,
“Time, Hour”,
“Time, Day”,
“Time, Month”,
“Logic Speed”,
“Reserved”,
“Reserved”,
“Reserved”,
“Reserved”,
“Reserved”,
“Reserved”,
“Reserved”,
“Reserved”,
“Reserved”,
“Reserved”,
“Reserved”,
“Reserved”,
“Reserved”,
“Reserved”,
“Reserved”,
“Reserved”,
“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”
};
#pragma pack(1)
typedef struct
{
unsigned char uid[16];
unsigned char node;
float data[128];
} REGISTERS;
#pragma push
char *json;
char hex[256][2] = {{‘0′,’0’},{‘0′,’1’},{‘0′,’2’},{‘0′,’3’},{‘0′,’4’},{‘0′,’5’},{‘0′,’6’},{‘0′,’7’},{‘0′,’8’},{‘0′,’9’},{‘0′,’a’},{‘0′,’b’},{‘0′,’c’},{‘0′,’d’},{‘0′,’e’},{‘0′,’f’},{‘1′,’0’},{‘1′,’1’},{‘1′,’2’},{‘1′,’3’},{‘1′,’4’},{‘1′,’5’},{‘1′,’6’},{‘1′,’7’},{‘1′,’8’},{‘1′,’9’},{‘1′,’a’},{‘1′,’b’},{‘1′,’c’},{‘1′,’d’},{‘1′,’e’},{‘1′,’f’},{‘2′,’0’},{‘2′,’1’},{‘2′,’2’},{‘2′,’3’},{‘2′,’4’},{‘2′,’5’},{‘2′,’6’},{‘2′,’7’},{‘2′,’8’},{‘2′,’9’},{‘2′,’a’},{‘2′,’b’},{‘2′,’c’},{‘2′,’d’},{‘2′,’e’},{‘2′,’f’},{‘3′,’0’},{‘3′,’1’},{‘3′,’2’},{‘3′,’3’},{‘3′,’4’},{‘3′,’5’},{‘3′,’6’},{‘3′,’7’},{‘3′,’8’},{‘3′,’9’},{‘3′,’a’},{‘3′,’b’},{‘3′,’c’},{‘3′,’d’},{‘3′,’e’},{‘3′,’f’},{‘4′,’0’},{‘4′,’1’},{‘4′,’2’},{‘4′,’3’},{‘4′,’4’},{‘4′,’5’},{‘4′,’6’},{‘4′,’7’},{‘4′,’8’},{‘4′,’9’},{‘4′,’a’},{‘4′,’b’},{‘4′,’c’},{‘4′,’d’},{‘4′,’e’},{‘4′,’f’},{‘5′,’0’},{‘5′,’1’},{‘5′,’2’},{‘5′,’3’},{‘5′,’4’},{‘5′,’5’},{‘5′,’6’},{‘5′,’7’},{‘5′,’8’},{‘5′,’9’},{‘5′,’a’},{‘5′,’b’},{‘5′,’c’},{‘5′,’d’},{‘5′,’e’},{‘5′,’f’},{‘6′,’0’},{‘6′,’1’},{‘6′,’2’},{‘6′,’3’},{‘6′,’4’},{‘6′,’5’},{‘6′,’6’},{‘6′,’7’},{‘6′,’8’},{‘6′,’9’},{‘6′,’a’},{‘6′,’b’},{‘6′,’c’},{‘6′,’d’},{‘6′,’e’},{‘6′,’f’},{‘7′,’0’},{‘7′,’1’},{‘7′,’2’},{‘7′,’3’},{‘7′,’4’},{‘7′,’5’},{‘7′,’6’},{‘7′,’7’},{‘7′,’8’},{‘7′,’9’},{‘7′,’a’},{‘7′,’b’},{‘7′,’c’},{‘7′,’d’},{‘7′,’e’},{‘7′,’f’},{‘8′,’0’},{‘8′,’1’},{‘8′,’2’},{‘8′,’3’},{‘8′,’4’},{‘8′,’5’},{‘8′,’6’},{‘8′,’7’},{‘8′,’8’},{‘8′,’9’},{‘8′,’a’},{‘8′,’b’},{‘8′,’c’},{‘8′,’d’},{‘8′,’e’},{‘8′,’f’},{‘9′,’0’},{‘9′,’1’},{‘9′,’2’},{‘9′,’3’},{‘9′,’4’},{‘9′,’5’},{‘9′,’6’},{‘9′,’7’},{‘9′,’8’},{‘9′,’9’},{‘9′,’a’},{‘9′,’b’},{‘9′,’c’},{‘9′,’d’},{‘9′,’e’},{‘9′,’f’},{‘a’,’0′},{‘a’,’1′},{‘a’,’2′},{‘a’,’3′},{‘a’,’4′},{‘a’,’5′},{‘a’,’6′},{‘a’,’7′},{‘a’,’8′},{‘a’,’9′},{‘a’,’a’},{‘a’,’b’},{‘a’,’c’},{‘a’,’d’},{‘a’,’e’},{‘a’,’f’},{‘b’,’0′},{‘b’,’1′},{‘b’,’2′},{‘b’,’3′},{‘b’,’4′},{‘b’,’5′},{‘b’,’6′},{‘b’,’7′},{‘b’,’8′},{‘b’,’9′},{‘b’,’a’},{‘b’,’b’},{‘b’,’c’},{‘b’,’d’},{‘b’,’e’},{‘b’,’f’},{‘c’,’0′},{‘c’,’1′},{‘c’,’2′},{‘c’,’3′},{‘c’,’4′},{‘c’,’5′},{‘c’,’6′},{‘c’,’7′},{‘c’,’8′},{‘c’,’9′},{‘c’,’a’},{‘c’,’b’},{‘c’,’c’},{‘c’,’d’},{‘c’,’e’},{‘c’,’f’},{‘d’,’0′},{‘d’,’1′},{‘d’,’2′},{‘d’,’3′},{‘d’,’4′},{‘d’,’5′},{‘d’,’6′},{‘d’,’7′},{‘d’,’8′},{‘d’,’9′},{‘d’,’a’},{‘d’,’b’},{‘d’,’c’},{‘d’,’d’},{‘d’,’e’},{‘d’,’f’},{‘e’,’0′},{‘e’,’1′},{‘e’,’2′},{‘e’,’3′},{‘e’,’4′},{‘e’,’5′},{‘e’,’6′},{‘e’,’7′},{‘e’,’8′},{‘e’,’9′},{‘e’,’a’},{‘e’,’b’},{‘e’,’c’},{‘e’,’d’},{‘e’,’e’},{‘e’,’f’},{‘f’,’0′},{‘f’,’1′},{‘f’,’2′},{‘f’,’3′},{‘f’,’4′},{‘f’,’5′},{‘f’,’6′},{‘f’,’7′},{‘f’,’8′},{‘f’,’9′},{‘f’,’a’},{‘f’,’b’},{‘f’,’c’},{‘f’,’d’},{‘f’,’e’},{‘f’,’f’}};
REGISTERS registers;
int main(void)
{
struct sockaddr_in myaddr; /* our address */
struct sockaddr_in remaddr; /* remote address */
socklen_t addrlen = sizeof(remaddr); /* length of addresses */
int recvlen; /* # bytes received */
int fd; /* our socket */
unsigned char buf[BUFSIZE]; /* receive buffer */
/* create a UDP socket */
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror(“cannot create socket\n”);
return 0;
}
/* bind the socket to any valid IP address and a specific port */
memset((char *)&myaddr, 0, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(PORT);
if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
perror(“bind failed”);
return 0;
}
json = malloc(10000); // Should be plenty
/* now loop, receiving data and loading what we recieved into emoncms */
for (;;) {
int d = recvfrom(fd, ®isters, BUFSIZE, 0, (struct sockaddr *)&remaddr, &addrlen);
printf(“Rcv: %d : %d\n”,d, sizeof(REGISTERS));
if(d == BUFSIZE){
int k = 1;
char buffer[128];
// strcat(json,””);
*json = ‘\0’;
sprintf(buffer,SERVER,registers.node);
strcat(json,buffer);
for( ;k < 128; k++){
char end = ‘,’;
if(k == 127){end = ‘ ‘;}
if(registers.data[k] == registers.data[k]){
sprintf(buffer,”%s:%f%c”,names[k], registers.data[k],end);
strcat(json,buffer);
}
}
// Convert the UID to a Hex String… 16 bytes -> 32 bytes
char uid[33];
int i;
for(i=0; i<16; i++) {
uid[i*2] = hex[registers.uid[i]][0];
uid[i*2+1] = hex[registers.uid[i]][1];
}
uid[32] = ‘\0′;
sprintf(buffer,”}&&apikey=%s\’ -O /dev/null”,uid);
strcat(json,buffer);
system(json); // execute the command
// printf(json);
}
}
close(fd);
return 0;
}