Редизайн на основе текущей ветки мейнстрима + новые устройства.
[rtl-433.git] / src / devices / efergy_optical.c
1 /* Efergy IR is a devices that periodically reports current energy consumption
2  * on frequency ~433.55 MHz. The data that is transmitted consists of 8
3  * bytes:
4  *
5  * Byte 1-4: Start bits (0000), then static data (probably device id)
6  * Byte 5-7: all zeros 
7  * Byte 8: Pulse Count
8  * Byte 9: sample frequency (15 seconds)
9  * Byte 10: seconds
10  * Byte 11: bytes0-10 crc16 xmodem XOR with FF
11  * Byte 12: ?crc16 xmodem
12  * if pulse count <3 then energy =(( pulsecount/impulse-perkwh) * (3600/seconds))
13  * else  energy= ((pulsecount/n_imp) * (3600/seconds))
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or
18  * (at your option) any later version.
19  */
20
21 #include "rtl_433.h"
22 #include "util.h"
23 #include "data.h"
24
25 static int efergy_optical_callback(bitbuffer_t *bitbuffer) {
26         unsigned num_bits = bitbuffer->bits_per_row[0];
27         uint8_t *bytes = bitbuffer->bb[0];
28         double energy, n_imp;
29         double pulsecount;
30         double seconds;
31         data_t *data;
32         char time_str[LOCAL_TIME_BUFLEN];
33         uint16_t crc;
34         uint16_t csum1;
35
36         if (num_bits < 64 || num_bits > 100){
37                 return 0;
38                 }
39
40         // The bit buffer isn't always aligned to the transmitted data, so
41         // search for data start and shift out the bits which aren't part
42         // of the data. The data always starts with 0000 (or 1111 if
43         // gaps/pulses are mixed up).
44         while ((bytes[0] & 0xf0) != 0xf0 && (bytes[0] & 0xf0) != 0x00)
45                 {
46                 num_bits -= 1;
47                 if (num_bits < 64)
48                         {
49                         return 0;
50                         }
51
52                 for (unsigned i = 0; i < (num_bits + 7) / 8; ++i)
53                         {
54                         bytes[i] <<= 1;
55                         bytes[i] |= (bytes[i + 1] & 0x80) >> 7;
56                         }
57                 }
58
59         // Sometimes pulses and gaps are mixed up. If this happens, invert
60         // all bytes to get correct interpretation.
61         if (bytes[0] & 0xf0){
62                 for (unsigned i = 0; i < 12; ++i) 
63                         {
64                         bytes[i] = ~bytes[i];
65                         }
66                 }
67
68          if (debug_output){ 
69                 fprintf(stdout,"Possible Efergy Optical: ");
70                 bitbuffer_print(bitbuffer);
71                 }
72         
73         // Calculate checksum for bytes[0..10]
74         // crc16 xmodem with start value of 0x00 and polynomic of 0x1021 is same as CRC-CCITT (0x0000)         
75         // start of data, length of data=10, polynomic=0x1021, init=0x0000        
76
77           csum1 = ((bytes[10]<<8)|(bytes[11]));
78
79           crc = crc16_ccitt(bytes, 10, 0x1021, 0x0);
80
81           if (crc == csum1)
82                 { 
83                 if (debug_output) {
84                 fprintf (stdout, "Checksum OK :) :)\n");
85                 fprintf (stdout, "Calculated crc is 0x%02X\n", crc);
86                 fprintf (stdout, "Received csum1 is 0x%02X\n", csum1);
87                 }
88                 // this setting depends on your electricity meter's optical output      
89                 n_imp = 3200;
90
91                 pulsecount =  bytes[8];
92                 seconds = bytes[10];
93
94                 //some logic for low pulse count not sure how I reached this formula
95                 if (pulsecount < 3)
96                         {
97                         energy = ((pulsecount/n_imp) * (3600/seconds));
98                         }
99                 else
100                         {
101                         energy = ((pulsecount/n_imp) * (3600/30));
102                         }
103                 //New code for calculating varous energy values for differing pulse-kwh values
104                         const int imp_kwh[] = {3200, 2000, 1000, 500, 0};
105                         for (unsigned i=0; imp_kwh[i] !=0; ++i) {
106                                 if (pulsecount < 3)
107                                         {
108                                         energy = ((pulsecount/imp_kwh[i]) * (3600/seconds));
109                                         }
110                                 else
111                                         {
112                                         energy = ((pulsecount/imp_kwh[i]) * (3600/30));
113                                         }
114                                 local_time_str(0, time_str);
115                                 data = data_make(
116                                                 "time",          "Time",            DATA_STRING, time_str,
117                                                 "model",         "Model",            DATA_STRING, "Efergy Optical", 
118                                                 "pulses",       "Pulse-rate",   DATA_FORMAT,"%i", DATA_INT, imp_kwh[i],
119                                                 "energy",       "Energy",     DATA_FORMAT,"%.03f KWh", DATA_DOUBLE, energy,
120                                                    NULL);
121                                 data_acquired_handler(data);
122                                 }
123                                 return 0;
124                 }
125                 
126                 else 
127                         {
128                         if (debug_output)
129                                 { 
130                                 fprintf (stdout, "Checksum not OK !!!\n");
131                                 fprintf(stdout, "Calculated crc is 0x%02X\n", crc);
132                                 fprintf(stdout, "Received csum1 is 0x%02X\n", csum1);
133                                 }
134                         }
135                 return 0;
136                 }
137                 
138 static char *output_fields[] = {
139         "time",
140         "model",
141         "pulses",
142         "energy",
143         NULL
144         };
145
146 r_device efergy_optical = {
147         .name           = "Efergy Optical",
148         .modulation     = FSK_PULSE_PWM_RAW,
149         .short_limit    = 92,
150         .long_limit     = 400,
151         .reset_limit    = 400,
152         .json_callback  = &efergy_optical_callback,
153         .disabled       = 0,
154         .demod_arg      = 0,
155         .fields        = output_fields
156 };