/* Remote Energy Diverter (RED) for surplus PV power Revision 1.2 Brian Drury 25/02/2013 The intended hardware is an Arduino uno with an added RFM12B but other simpler configurations are possible An associated master dump controller sends periodic data blocks to wireless display units called emonGLCD These data blocks contain a control parameter emontx.ext_divert which is used by this code to control the state of a triac which is connectd to an additional dump load. Data packets are sent every few seconds but this is too slow for an energy diverter so the master sends an extra packet immediately when a change of state is required in the remote triac. The logic of this code is: loop { if(rx) { if(ON) { load ON time = clock } if(OFF) { load OFF time = 0 } } if(time > max) { load OFF error LED ON } } */ #include // Required to support the RFM12B // The RTC lib is used simply because it's the easiest way to produce millisecond timing // It would be more elegant and sensible to use a hardware timer and not include the RTC library but if this approach // works then why bother #include // Real time clock (RTC) #include // Part of Arduino libraries - needed for RTClib RTC_Millis RTC; //-------------------------------------------------------------------------------------------- // RFM12B Settings //-------------------------------------------------------------------------------------------- #define freq RF12_433MHZ // frequency - match to same frequency as RFM12B module (change to 868Mhz or 915Mhz if appropriate) #define group 210 // network group, must be same as emonTx and emonBase #define MYNODE 20 // In case we want to transmit #define ON_time_limit 5000 // Maximum ON time duration difference between two ON commands //--------------------------------------------------- // Data structure for transfering data between units // Most of these parameters are not required for RED //--------------------------------------------------- typedef struct { int power1, power2, power3, Vrms, temp, frequency, ext_divert; } PayloadTX; // neat way of packaging data for RF comms PayloadTX emontx; // The external controller has four LED's these are defined here byte red_led_1 = 6; // Receive error - CRC etc byte amber_led = 3; // Toggled on every packet received byte green_led = 4; // Dumping (Triac on) byte red_led_2 = 5; // Timeout LED - used for triac auto off and no received packets byte arduino_led = 13; // This is the LED on the Arduino PCB byte triac = 9; // Triac drive byte toggle = 0; #define ON 0 // the external trigger device is active low #define OFF 1 //-------------------------------------------------------------------------------------------- // Flow control //-------------------------------------------------------------------------------------------- unsigned long last_emontx; // Used to count time from last emontx update unsigned long this_ON_time; // Current ON timer //-------------------------------------------------------------------------------------------- // Setup //-------------------------------------------------------------------------------------------- void setup() { Serial.begin(9600); rf12_initialize(MYNODE, freq,group); pinMode(triac, OUTPUT); pinMode(arduino_led, OUTPUT); pinMode(red_led_1, OUTPUT); pinMode(amber_led, OUTPUT); pinMode(green_led, OUTPUT); pinMode(red_led_2, OUTPUT); // ************************************************************************* // Initialise with LED's off digitalWrite(red_led_1,OFF); digitalWrite(amber_led,OFF); digitalWrite(green_led,OFF); digitalWrite(red_led_2,OFF); digitalWrite(arduino_led, 0); // active high // ************************************************************************* last_emontx = millis(); // Rewind the emontx timer } /* This code is designed to monitor a transmission block from a emonTX master dump controller and when instructed will switch on a triac to enable excess PV power to be put to good use at a point remote from the master */ void loop() { if (rf12_recvDone()) // Check if anything received { // Serial.println("Something received "); if (rf12_crc == 0 && (rf12_hdr & RF12_HDR_CTL) == 0) // and no rf errors { digitalWrite(red_led_1,OFF); toggle = !toggle; digitalWrite(amber_led,toggle); int node_id = (rf12_hdr & 0x1F); // strip some bits if (node_id == 10) // Is it from the master controller? { digitalWrite(red_led_2,OFF); // Turn off the error LED if this is a good packet from the master /* Here to process a transmission from the emontx, these arrive periodically every few seconds but in addition if a change of state is rquired the master will send a transmission early */ emontx = *(PayloadTX*) rf12_data; // Point to the packet last_emontx = millis(); // Rewind the timer /* The only parameter we are interested in is emontx.ext_divert Non zero means apply power, zero means switch off The MOC 30xx zero crossing detector will trigger when enabled and MT1-MT2 < 20V Robin's mk2 sketch makes sure that the MOV LED is only turned on when the mains is above 20V this will ensure that the load is not turrned on until the start of the next half cycle. If we also wish to ensure that only complete half cycles are used then it will be necessary to include voltage monitoring software and hardware to determine when the mains voltage exceeds 20V so that the MOC can be switched on ready This looks sensible except that the only advantage that I can see is the triac will be switched on at the same point in the first half cycle as in following half cycles. In a burst fire controller this is unimportant therefore the voltage monitor will not be used in this controller. If a command to switch the load on or off is received it will be actioned as quickly as possible */ // Serial.println(emontx.ext_divert); if (emontx.ext_divert) // Check if an ON command has been received { digitalWrite (triac, ON); // Switch ON the load digitalWrite(green_led,ON); // Switch ON the LED this_ON_time = millis(); // Remember when it was done } else { // Must be an OFF command digitalWrite (triac, OFF); // Switch OFF the load digitalWrite(green_led,OFF); // Switch OFF the LED this_ON_time = 0; // Ready for next time } } } else { // Receive error. These happen quite often due to multiple transmitters in the vicinity // The safest thing to do is switch of the load as this will allow the secondary load to take over digitalWrite(red_led_1,ON); digitalWrite (triac, OFF); // Switch OFF the load digitalWrite(green_led,OFF); // Switch OFF the LED } } // If no commands are received from the master for 5 seconds then something is wrong so the triac is switched off if ((millis() - last_emontx) > 5000) // Is it 5 seconds since the last transmission? { digitalWrite (triac, OFF); // Switch OFF the load digitalWrite(green_led,OFF); // Switch OFF the LED digitalWrite(red_led_2,ON); // Switch ON the error LED digitalWrite(amber_led,OFF); // Toggle off // Serial.println("Nothing received "); } /* Check to see how long the triac has been on for in case we have missed an OFF command */ if((this_ON_time) && (millis() - this_ON_time) > ON_time_limit) { // Here if the triac has been on for too long digitalWrite (triac, OFF); // Switch OFF the load digitalWrite(green_led,OFF); // Switch OFF the LED /* // Some diagnostics Serial.println(this_ON_time); Serial.println(millis() ); Serial.println((millis() - this_ON_time)); Serial.println(last_ON_duration); */ this_ON_time = 0; // Ready for next time digitalWrite(red_led_2,ON); // Turn on the triac timeout LED // Serial.println("Timed out"); } }