Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include<stdlib.h>
- #include <SoftwareSerial.h>
- /*
- Reads voltage and power from China-style energy meter.
- Collecting data by eavesdropping on the MOSI-line (master in slave out)
- between the energy monitoring chip (ECH1560) and the main processor*/
- const int CLKPin = 2; // Pin connected to CLK (D2 & INT0)
- const int MISOPin = 5; // Pin connected to MISO (D5)
- //All variables that is changed in the interrupt function must be volatile to make sure changes are saved.
- volatile int Ba = 0; //Store MISO-byte 1
- volatile int Bb = 0; //Store MISO-byte 2
- volatile int Bc = 0; //Store MISO-byte 2
- float U = 0; //voltage
- float P = 0; //power
- float ReadData[3] = {0, 0, 0}; //Array to hold mean values of [U,I,P]
- volatile long CountBits = 0; //Count read bits
- volatile int Antal = 0; //number of read values (to calculate mean)
- volatile long ClkHighCount = 0; //Number of CLK-highs (find start of a Byte)
- volatile boolean inSync = false; //as long as we ar in SPI-sync
- volatile boolean NextBit = true; //A new bit is detected
- #define SSID "SSID_HERE" //Put SSID here, leave quotes
- #define PASS "PASSWORD" //Put password here, leave quotes
- #define IP "192.168.4.4" // Domoticz address
- #define PORT "8084" //Port where Domoticz is running, not working yet.
- String GET = "GET /json.htm?type=command¶m=udevice&idx="; //Domoticz JSON URL
- String IDX = "52"; //IDX value of virtual sensor in Domoticz
- String GET2 = "&nvalue=0&svalue="; //Second part of Domoticz JSON URL
- String GET3 = ";0"; //ENERGY part (last part of Domoticz JSON URL)
- SoftwareSerial monitor(10, 11); // Use these pins to monitor the Arduino from the PC. Hardware pins are used for ESP8266
- String AmountOfWatts;
- void setup() {
- //Setting up interrupt ISR on D2 (INT0), trigger function "CLK_ISR()" when INT0 (CLK)is rising
- attachInterrupt(0, CLK_ISR, RISING);
- //Set the CLK-pin (D5) to input
- pinMode(CLKPin, INPUT);
- //Set the MISO-pin (D5) to input
- pinMode(MISOPin, INPUT);
- // initialize serial communications at 9600 bps: (to computer)
- monitor.begin(9600);
- Serial.begin(9600);
- sendDebug("AT");
- delay(5000);
- if(Serial.find("OK")){
- monitor.println("RECEIVED: OK");
- //connectWiFi();
- }
- }
- void loop() {
- //do nothing until the CLK-interrupt occures and sets inSync=true
- if(inSync == true){
- CountBits = 0; //CLK-interrupt increments CountBits when new bit is received
- while(CountBits<40){} //skip the uninteresting 5 first bytes
- CountBits=0;
- Ba=0;
- Bb=0;
- while(CountBits<24){ //Loop through the next 3 Bytes (6-8) and save byte 6 and 7 in Ba and Bb
- if(NextBit == true){ //when rising edge on CLK is detected, NextBit = true in in interrupt.
- if(CountBits < 9){ //first Byte/8 bits in Ba
- Ba = (Ba << 1); //Shift Ba one bit to left and store MISO-value (0 or 1) (see http://arduino.cc/en/Reference/Bitshift)
- //read MISO-pin, if high: make Ba[0] = 1
- if(digitalRead(MISOPin)==HIGH){
- Ba |= (1<<0); //changes first bit of Ba to "1"
- } //doesn't need "else" because BaBb[0] is zero if not changed.
- NextBit=false; //reset NextBit in wait for next CLK-interrupt
- }
- else if(CountBits < 17){ //bit 9-16 is byte 7, stor in Bb
- Bb = Bb << 1; //Shift Ba one bit to left and store MISO-value (0 or 1)
- //read MISO-pin, if high: make Ba[0] = 1
- if(digitalRead(MISOPin)==HIGH){
- Bb |= (1<<0); //changes first bit of Bb to "1"
- }
- NextBit=false; //reset NextBit in wait for next CLK-interrupt
- }
- }
- }
- if(Bb!=3){ //if bit Bb is not 3, we have reached the important part, U is allready in Ba and Bb and next 8 Bytes will give us the Power.
- Antal += 1; //increment for mean value calculations
- //Voltage = 2*(Ba+Bb/255)
- U=2.0*((float)Ba+(float)Bb/255.0);
- //Power:
- CountBits=0;
- while(CountBits<40){}//Start reading the next 8 Bytes by skipping the first 5 uninteresting ones
- CountBits=0;
- Ba=0;
- Bb=0;
- Bc=0;
- while(CountBits<24){ //store byte 6, 7 and 8 in Ba and Bb & Bc.
- if(NextBit == true){
- if(CountBits < 9){
- Ba = (Ba << 1); //Shift Ba one bit to left and store MISO-value (0 or 1)
- //read MISO-pin, if high: make Ba[0] = 1
- if(digitalRead(MISOPin)==HIGH){
- Ba |= (1<<0); //changes first bit of Ba to "1"
- }
- NextBit=false;
- }
- else if(CountBits < 17){
- Bb = Bb << 1; //Shift Ba one bit to left and store MISO-value (0 or 1)
- //read MISO-pin, if high: make Ba[0] = 1
- if(digitalRead(MISOPin)==HIGH){
- Bb |= (1<<0); //changes first bit of Bb to "1"
- }
- NextBit=false;
- }
- else{
- Bc = Bc << 1; //Shift Bc one bit to left and store MISO-value (0 or 1)
- //read MISO-pin, if high: make Bc[0] = 1
- if(digitalRead(MISOPin)==HIGH){
- Bc |= (1<<0); //changes first bit of Bc to "1"
- }
- NextBit=false;
- }
- }
- }
- ////////////////////////
- Ba=255-Ba;
- Bb=255-Bb;
- Bc=255-Bc;
- ///////////////////Needed for my China meter, remove if power calculation is not done correctly!
- //Power = (Ba*255+Bb)/2
- P=((float)Ba*255+(float)Bb+(float)Bc/255.0)/2;
- //Convert power (float) to string
- static char outstr[15];
- AmountOfWatts = dtostrf(P,4,1,outstr); //4 digits, 1 decimal.... needs to be looked at, not done yet
- //Voltage mean
- ReadData[0] = (U+ReadData[0]*((float)Antal-1))/(float)Antal;
- //Current mean
- ReadData[1] = (P/U+ReadData[1]*((float)Antal-1))/(float)Antal;
- //Power mean
- ReadData[2] = (P+ReadData[2]*((float)Antal-1))/(float)Antal;
- //Print out results (i skipped the mean values since the actual ones are very stable)
- monitor.print("U: ");
- monitor.print(U,1);
- monitor.println("V");
- monitor.print("I: ");
- monitor.print(P/U*1000,0); //I=P/U and in milli ampere
- monitor.println("mA");
- monitor.print("P: ");
- monitor.print(P,1);
- monitor.println("W");
- monitor.println("");
- if(Antal==10){ //every 10th 70-package = every ~10s
- //transmit ReadData-array to nRF or Wifi-module here:
- //transmission function here...
- SendToDomoticz(AmountOfWatts);
- //Reset ReadData-array
- ReadData[0] = 0;
- ReadData[1] = 0;
- ReadData[2] = 0;
- //reset mean-value counter
- Antal=0;
- }
- inSync=false; //reset sync variable to make sure next reading is in sync.
- }
- if(Bb==0){ //If Bb is not 3 or something else than 0, something is wrong!
- inSync=false;
- monitor.println("Nothing connected, or out of sync!");
- }
- }
- }
- //Function that triggers whenever CLK-pin is rising (goes high)
- void CLK_ISR(){
- //if we are trying to find the sync-time (CLK goes high for 1-2ms)
- if(inSync==false){
- ClkHighCount = 0;
- //Register how long the ClkHigh is high to evaluate if we are at the part wher clk goes high for 1-2 ms
- while(digitalRead(CLKPin)==HIGH){
- ClkHighCount += 1;
- delayMicroseconds(30); //can only use delayMicroseconds in an interrupt.
- }
- //if the Clk was high between 1 and 2 ms than, its a start of a SPI-transmission
- if(ClkHighCount >= 33 && ClkHighCount <= 67){
- inSync = true;
- }
- }
- else{ //we are in sync and logging CLK-highs
- //increment an integer to keep track of how many bits we have read.
- CountBits += 1;
- NextBit = true;
- }
- }
- boolean connectWiFi(){
- Serial.println("AT+CWMODE=1");
- delay(2000);
- //String cmd="AT+CWJAP=\"";
- //cmd+=SSID;
- //cmd+="\",\"";
- //cmd+=PASS;
- //cmd+="\"";
- //sendDebug(cmd);
- //delay(5000);
- //if(Serial.find("OK")){
- // monitor.println("RECEIVED: OK (connectWiFi)");
- // return true;
- //}else{
- // monitor.println("RECEIVED: Error (connectWiFi)");
- // return false;
- return true;
- //}
- }
- void sendDebug(String cmd){
- monitor.print("SEND: ");
- monitor.println(cmd);
- Serial.println(cmd);
- }
- void SendToDomoticz(String AmountOfWatts){
- String cmd = "AT+CIPSTART=\"TCP\",\""; //make this command: AT+CPISTART="TCP","192.168.4.4",8084
- cmd += IP;
- cmd += "\",8084"; //Domoticz is running on port 8084... needs to be changed into a variable that is set on top of sketch
- sendDebug(cmd);
- delay(2000); //wait a little while for 'Linked' response - this makes a difference
- if(Serial.find("Linked")) {
- monitor.println("Linked!");
- }
- cmd = GET;
- cmd += IDX;
- cmd += GET2;
- cmd += AmountOfWatts;
- cmd += GET3;
- cmd += " HTTP/1.0\r\n"; //construct http GET request
- cmd += "Host: 192.168.4.4\r\n\r\n"; //Domoticz IP > Needs to be changed into variable that is set on top of sketch
- Serial.print("AT+CIPSEND=");
- Serial.println(cmd.length()); //esp8266 needs to know message length of incoming message - .length provides this
- if(Serial.find(">")) //prompt offered by esp8266
- {
- monitor.println("found > prompt - issuing GET request"); //a debug message
- Serial.println(cmd); //this is our http GET request
- }
- else
- {
- Serial.println("AT+CIPCLOSE");
- monitor.println("No '>' prompt received after AT+CPISEND");
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement