9#ifdef MYCILA_LOGGER_SUPPORT
10 #include <MycilaLogger.h>
11extern Mycila::Logger logger;
12 #define LOGD(tag, format, ...) logger.debug(tag, format, ##__VA_ARGS__)
13 #define LOGI(tag, format, ...) logger.info(tag, format, ##__VA_ARGS__)
14 #define LOGW(tag, format, ...) logger.warn(tag, format, ##__VA_ARGS__)
15 #define LOGE(tag, format, ...) logger.error(tag, format, ##__VA_ARGS__)
17 #define LOGD(tag, format, ...) ESP_LOGD(tag, format, ##__VA_ARGS__)
18 #define LOGI(tag, format, ...) ESP_LOGI(tag, format, ##__VA_ARGS__)
19 #define LOGW(tag, format, ...) ESP_LOGW(tag, format, ##__VA_ARGS__)
20 #define LOGE(tag, format, ...) ESP_LOGE(tag, format, ##__VA_ARGS__)
23#ifndef GPIO_IS_VALID_OUTPUT_GPIO
24 #define GPIO_IS_VALID_OUTPUT_GPIO(gpio_num) ((gpio_num >= 0) && \
25 (((1ULL << (gpio_num)) & SOC_GPIO_VALID_OUTPUT_GPIO_MASK) != 0))
28#ifndef GPIO_IS_VALID_GPIO
29 #define GPIO_IS_VALID_GPIO(gpio_num) ((gpio_num >= 0) && \
30 (((1ULL << (gpio_num)) & SOC_GPIO_VALID_GPIO_MASK) != 0))
33#define LOBYTE(x) ((uint8_t)((x) & 0xFF))
34#define HIBYTE(x) ((uint8_t)((x) >> 8))
37#define JSY_LOCK_TIMEOUT 2000
44#define JSY_REGISTER_MODEL1 0x0000
45#define JSY_REGISTER_MODEL2 0x0001
46#define JSY_REGISTER_VOLTAGE_RANGE 0x0002
47#define JSY_REGISTER_CURRENT_RANGE 0x0003
50#define JSY_REGISTER_ID_AND_BAUDS 0x0004
51#define JSY_REGISTER_SWITCH_MODE 0x0005
52#define JSY_MODE_AC 0x01
53#define JSY_MODE_DC 0x02
59#define JSY_1031_REGISTER_VOLTAGE 0x0048
60#define JSY_1031_REGISTER_CURRENT 0x0049
61#define JSY_1031_REGISTER_ACTIVE_POWER 0x004B
62#define JSY_1031_REGISTER_ACTIVE_ENERGY 0x004D
63#define JSY_1031_REGISTER_POWER_FACTOR 0x004F
64#define JSY_1031_REGISTER_FREQUENCY 0x0050
65#define JSY_1031_REGISTER_CO2 0x0051
66#define JSY_1031_REGISTER_RESERVED 0x0053
67#define JSY_1031_REGISTER_APPARENT_POWER 0x0057
68#define JSY_1031_REGISTER_REACTIVE_POWER 0x0059
69#define JSY_1031_REGISTER_PHASE_ANGLE 0x005B
71#define JSY_1031_REGISTER_LEN 2
72#define JSY_1031_REGISTER_COUNT 19
73#define JSY_1031_REGISTER_START JSY_1031_REGISTER_VOLTAGE
79#define JSY_163_REGISTER_VOLTAGE 0x0048
80#define JSY_163_REGISTER_CURRENT 0x0049
81#define JSY_163_REGISTER_ACTIVE_POWER 0x004A
82#define JSY_163_REGISTER_ACTIVE_ENERGY_IMPORTED 0x004B
83#define JSY_163_REGISTER_POWER_FACTOR 0x004D
84#define JSY_163_REGISTER_ACTIVE_ENERGY_RETURNED 0x004E
85#define JSY_163_REGISTER_ACTIVE_POWER_SIGN 0x0050
86#define JSY_163_REGISTER_FREQUENCY 0x0051
88#define JSY_163_REGISTER_LEN 2
89#define JSY_163_REGISTER_COUNT 10
90#define JSY_163_REGISTER_START JSY_163_REGISTER_VOLTAGE
96#define JSY_193_REGISTER_CH1_VOLTAGE 0x0100
97#define JSY_193_REGISTER_CH1_CURRENT 0x0101
98#define JSY_193_REGISTER_CH1_ACTIVE_POWER 0x0102
99#define JSY_193_REGISTER_CH1_ACTIVE_POWER_SIGN 0x0103
100#define JSY_193_REGISTER_CH1_ACTIVE_ENERGY_POSITIVE 0x0104
101#define JSY_193_REGISTER_CH1_ACTIVE_ENERGY_NEGATIVE 0x0106
102#define JSY_193_REGISTER_CH1_POWER_FACTOR 0x0108
103#define JSY_193_REGISTER_CH1_FREQUENCY 0x0109
104#define JSY_193_REGISTER_CH2_VOLTAGE 0x010A
105#define JSY_193_REGISTER_CH2_CURRENT 0x010B
106#define JSY_193_REGISTER_CH2_ACTIVE_POWER 0x010C
107#define JSY_193_REGISTER_CH2_ACTIVE_POWER_SIGN 0x010D
108#define JSY_193_REGISTER_CH2_ACTIVE_ENERGY_POSITIVE 0x010E
109#define JSY_193_REGISTER_CH2_ACTIVE_ENERGY_NEGATIVE 0x0110
110#define JSY_193_REGISTER_CH2_POWER_FACTOR 0x0112
111#define JSY_193_REGISTER_CH2_FREQUENCY 0x0113
113#define JSY_193_REGISTER_LEN 2
114#define JSY_193_REGISTER_COUNT 20
115#define JSY_193_REGISTER_START JSY_193_REGISTER_CH1_VOLTAGE
121#define JSY_194_REGISTER_CH1_VOLTAGE 0x0048
122#define JSY_194_REGISTER_CH1_CURRENT 0x0049
123#define JSY_194_REGISTER_CH1_ACTIVE_POWER 0x004A
124#define JSY_194_REGISTER_CH1_ACTIVE_ENERGY_IMPORTED 0x004B
125#define JSY_194_REGISTER_CH1_POWER_FACTOR 0x004C
126#define JSY_194_REGISTER_CH1_ACTIVE_ENERGY_RETURNED 0x004D
127#define JSY_194_REGISTER_ACTIVE_POWER_SIGNS 0x004E
128#define JSY_194_REGISTER_FREQUENCY 0x004F
129#define JSY_194_REGISTER_CH2_VOLTAGE 0x0050
130#define JSY_194_REGISTER_CH2_CURRENT 0x0051
131#define JSY_194_REGISTER_CH2_ACTIVE_POWER 0x0052
132#define JSY_194_REGISTER_CH2_ACTIVE_ENERGY_IMPORTED 0x0053
133#define JSY_194_REGISTER_CH2_POWER_FACTOR 0x0054
134#define JSY_194_REGISTER_CH2_ACTIVE_ENERGY_RETURNED 0x0055
136#define JSY_194_REGISTER_LEN 4
137#define JSY_194_REGISTER_COUNT 14
138#define JSY_194_REGISTER_START JSY_194_REGISTER_CH1_VOLTAGE
144#define JSY_22x_REGISTER_VOLTAGE 0x0100
145#define JSY_22x_REGISTER_CURRENT 0x0102
146#define JSY_22x_REGISTER_ACTIVE_POWER 0x0104
147#define JSY_22x_REGISTER_REACTIVE_POWER 0x0106
148#define JSY_22x_REGISTER_APPARENT_POWER 0x0108
149#define JSY_22x_REGISTER_POWER_FACTOR 0x010A
150#define JSY_22x_REGISTER_FREQUENCY 0x010C
151#define JSY_22x_REGISTER_ACTIVE_ENERGY 0x010E
152#define JSY_22x_REGISTER_REACTIVE_ENERGY 0x0110
153#define JSY_22x_REGISTER_POWER_SUPPLY 0x0112
154#define JSY_22x_REGISTER_ACTIVE_POWER_SIGN 0x0114
155#define JSY_22x_REGISTER_REACTIVE_POWER_SIGN 0x0115
156#define JSY_22x_REGISTER_ACTIVE_ENERGY_POSITIVE 0x0116
157#define JSY_22x_REGISTER_ACTIVE_ENERGY_NEGATIVE 0x0118
158#define JSY_22x_REGISTER_REACTIVE_ENERGY_POSITIVE 0x011A
159#define JSY_22x_REGISTER_REACTIVE_ENERGY_NEGATIVE 0x011C
161#define JSY_22x_REGISTER_LEN 2
162#define JSY_22x_REGISTER_COUNT 30
163#define JSY_22x_REGISTER_START JSY_22x_REGISTER_VOLTAGE
169#define JSY_333_REGISTER_PHASE_A_VOLTAGE 0x0100
170#define JSY_333_REGISTER_PHASE_B_VOLTAGE 0x0101
171#define JSY_333_REGISTER_PHASE_C_VOLTAGE 0x0102
172#define JSY_333_REGISTER_PHASE_A_CURRENT 0x0103
173#define JSY_333_REGISTER_PHASE_B_CURRENT 0x0104
174#define JSY_333_REGISTER_PHASE_C_CURRENT 0x0105
175#define JSY_333_REGISTER_PHASE_A_ACTIVE_POWER 0x0106
176#define JSY_333_REGISTER_PHASE_B_ACTIVE_POWER 0x0107
177#define JSY_333_REGISTER_PHASE_C_ACTIVE_POWER 0x0108
178#define JSY_333_REGISTER_TOTAL_ACTIVE_POWER 0x0109
179#define JSY_333_REGISTER_PHASE_A_REACTIVE_POWER 0x010B
180#define JSY_333_REGISTER_PHASE_B_REACTIVE_POWER 0x010C
181#define JSY_333_REGISTER_PHASE_C_REACTIVE_POWER 0x010D
182#define JSY_333_REGISTER_TOTAL_REACTIVE_POWER 0x010E
183#define JSY_333_REGISTER_PHASE_A_APPARENT_POWER 0x0110
184#define JSY_333_REGISTER_PHASE_B_APPARENT_POWER 0x0111
185#define JSY_333_REGISTER_PHASE_C_APPARENT_POWER 0x0112
186#define JSY_333_REGISTER_TOTAL_APPARENT_POWER 0x0113
187#define JSY_333_REGISTER_FREQUENCY 0x0115
188#define JSY_333_REGISTER_PHASE_A_POWER_FACTOR 0x0116
189#define JSY_333_REGISTER_PHASE_B_POWER_FACTOR 0x0117
190#define JSY_333_REGISTER_PHASE_C_POWER_FACTOR 0x0118
191#define JSY_333_REGISTER_TOTAL_POWER_FACTOR 0x0119
192#define JSY_333_REGISTER_PHASE_A_ACTIVE_ENERGY 0x011A
193#define JSY_333_REGISTER_PHASE_B_ACTIVE_ENERGY 0x011C
194#define JSY_333_REGISTER_PHASE_C_ACTIVE_ENERGY 0x011E
195#define JSY_333_REGISTER_TOTAL_ACTIVE_ENERGY 0x0120
196#define JSY_333_REGISTER_PHASE_A_REACTIVE_ENERGY 0x0122
197#define JSY_333_REGISTER_PHASE_B_REACTIVE_ENERGY 0x0124
198#define JSY_333_REGISTER_PHASE_C_REACTIVE_ENERGY 0x0126
199#define JSY_333_REGISTER_TOTAL_REACTIVE_ENERGY 0x0128
200#define JSY_333_REGISTER_PHASE_A_APPARENT_ENERGY 0x012A
201#define JSY_333_REGISTER_PHASE_B_APPARENT_ENERGY 0x012C
202#define JSY_333_REGISTER_PHASE_C_APPARENT_ENERGY 0x012E
203#define JSY_333_REGISTER_TOTAL_APPARENT_ENERGY 0x0130
204#define JSY_333_REGISTER_POWER_SIGNS 0x0132
205#define JSY_333_REGISTER_ALARMS 0x0133
206#define JSY_333_REGISTER_PHASE_A_ACTIVE_ENERGY_IMPORTED 0x0134
207#define JSY_333_REGISTER_PHASE_B_ACTIVE_ENERGY_IMPORTED 0x0136
208#define JSY_333_REGISTER_PHASE_C_ACTIVE_ENERGY_IMPORTED 0x0138
209#define JSY_333_REGISTER_TOTAL_ACTIVE_ENERGY_IMPORTED 0x013A
210#define JSY_333_REGISTER_PHASE_A_ACTIVE_ENERGY_RETURNED 0x013C
211#define JSY_333_REGISTER_PHASE_B_ACTIVE_ENERGY_RETURNED 0x013E
212#define JSY_333_REGISTER_PHASE_C_ACTIVE_ENERGY_RETURNED 0x0140
213#define JSY_333_REGISTER_TOTAL_ACTIVE_ENERGY_RETURNED 0x0142
214#define JSY_333_REGISTER_PHASE_A_REACTIVE_ENERGY_IMPORTED 0x0144
215#define JSY_333_REGISTER_PHASE_B_REACTIVE_ENERGY_IMPORTED 0x0146
216#define JSY_333_REGISTER_PHASE_C_REACTIVE_ENERGY_IMPORTED 0x0148
217#define JSY_333_REGISTER_TOTAL_REACTIVE_ENERGY_IMPORTED 0x014A
218#define JSY_333_REGISTER_PHASE_A_REACTIVE_ENERGY_RETURNED 0x014C
219#define JSY_333_REGISTER_PHASE_B_REACTIVE_ENERGY_RETURNED 0x014E
220#define JSY_333_REGISTER_PHASE_C_REACTIVE_ENERGY_RETURNED 0x0150
221#define JSY_333_REGISTER_TOTAL_REACTIVE_ENERGY_RETURNED 0x0152
222#define JSY_333_REGISTER_PHASE_A_L_U 0x0154
223#define JSY_333_REGISTER_PHASE_B_L_U 0x0155
224#define JSY_333_REGISTER_PHASE_C_L_U 0x0156
225#define JSY_333_REGISTER_PHASE_A_PHASE_ANGLE_U 0x0157
226#define JSY_333_REGISTER_PHASE_B_PHASE_ANGLE_U 0x0158
227#define JSY_333_REGISTER_PHASE_C_PHASE_ANGLE_U 0x0159
228#define JSY_333_REGISTER_PHASE_A_PHASE_ANGLE_I 0x015A
229#define JSY_333_REGISTER_PHASE_B_PHASE_ANGLE_I 0x015B
230#define JSY_333_REGISTER_PHASE_C_PHASE_ANGLE_I 0x015C
231#define JSY_333_REGISTER_PHASE_A_PHASE_ANGLE_UI 0x015D
232#define JSY_333_REGISTER_PHASE_B_PHASE_ANGLE_UI 0x015E
233#define JSY_333_REGISTER_PHASE_C_PHASE_ANGLE_UI 0x015F
234#define JSY_333_REGISTER_PHASE_A_THD_U 0x0160
235#define JSY_333_REGISTER_PHASE_B_THD_U 0x0161
236#define JSY_333_REGISTER_PHASE_C_THD_U 0x0162
237#define JSY_333_REGISTER_PHASE_A_THD_I 0x0163
238#define JSY_333_REGISTER_PHASE_B_THD_I 0x0164
239#define JSY_333_REGISTER_PHASE_C_THD_I 0x0165
241#define JSY_333_REGISTER_LEN 2
242#define JSY_333_REGISTER_COUNT 102
243#define JSY_333_REGISTER_START JSY_333_REGISTER_PHASE_A_VOLTAGE
250#define JSY_CMD_READ_REGISTERS 0x03
251#define JSY_CMD_READ_RELAY1 0x01
252#define JSY_CMD_WRITE_REGISTERS 0x10
253#define JSY_CMD_WRITE_RELAY1 0x05
256#define JSY_REQUEST_ADDRESS 0
257#define JSY_REQUEST_CMD 1
258#define JSY_REQUEST_READ_REGISTER_ADDR_HIGH 2
259#define JSY_REQUEST_READ_REGISTER_ADDR_LOW 3
260#define JSY_REQUEST_READ_REGISTER_COUNT_HIGH 4
261#define JSY_REQUEST_READ_REGISTER_COUNT_LOW 5
262#define JSY_REQUEST_SET_ADDRESS 7
263#define JSY_REQUEST_SET_BAUDS 8
264#define JSY_REQUEST_SET_MODE 8
267#define JSY_RESPONSE_ADDRESS 0
268#define JSY_RESPONSE_CMD 1
269#define JSY_RESPONSE_DATA_LEN 2
270#define JSY_RESPONSE_DATA 3
273#define JSY_RESPONSE_SIZE_READ 5
274#define JSY_RESPONSE_SIZE_READ_MODEL JSY_RESPONSE_SIZE_READ + 2
275#define JSY_RESPONSE_SIZE_READ_MODE JSY_RESPONSE_SIZE_READ_MODEL
276#define JSY_RESPONSE_SIZE_RESET_ENERGY 8
277#define JSY_RESPONSE_SIZE_SWITCH_MODE 8
278#define JSY_RESPONSE_SIZE_SET_COM 8
280static constexpr uint8_t JSY_REQUEST_READ_REGISTERS[] = {
281 MYCILA_JSY_ADDRESS_BROADCAST,
282 JSY_CMD_READ_REGISTERS,
290static constexpr size_t JSY_REQUEST_READ_REGISTERS_LEN =
sizeof(JSY_REQUEST_READ_REGISTERS);
292static constexpr uint8_t JSY_REQUEST_READ_MODEL[] = {
293 MYCILA_JSY_ADDRESS_BROADCAST,
294 JSY_CMD_READ_REGISTERS,
295 HIBYTE(JSY_REGISTER_MODEL1),
296 LOBYTE(JSY_REGISTER_MODEL1),
302static constexpr size_t JSY_REQUEST_READ_MODEL_LEN =
sizeof(JSY_REQUEST_READ_MODEL);
304static constexpr uint8_t JSY_REQUEST_READ_MODE[] = {
305 MYCILA_JSY_ADDRESS_BROADCAST,
306 JSY_CMD_READ_REGISTERS,
307 HIBYTE(JSY_REGISTER_MODEL2),
308 LOBYTE(JSY_REGISTER_MODEL2),
314static constexpr size_t JSY_REQUEST_READ_MODE_LEN =
sizeof(JSY_REQUEST_READ_MODE);
316static constexpr uint8_t JSY_REQUEST_RESET_ENERGY[] = {
317 MYCILA_JSY_ADDRESS_BROADCAST,
318 JSY_CMD_WRITE_REGISTERS,
331static constexpr size_t JSY_REQUEST_RESET_ENERGY_LEN =
sizeof(JSY_REQUEST_RESET_ENERGY);
333static constexpr uint8_t JSY_REQUEST_SET_COM[] = {
334 MYCILA_JSY_ADDRESS_BROADCAST,
335 JSY_CMD_WRITE_REGISTERS,
336 HIBYTE(JSY_REGISTER_ID_AND_BAUDS),
337 LOBYTE(JSY_REGISTER_ID_AND_BAUDS),
346static constexpr size_t JSY_REQUEST_SET_COM_LEN =
sizeof(JSY_REQUEST_SET_COM);
348static constexpr uint8_t JSY_REQUEST_SWITCH_MODE[] = {
349 MYCILA_JSY_ADDRESS_BROADCAST,
350 JSY_CMD_WRITE_REGISTERS,
351 HIBYTE(JSY_REGISTER_SWITCH_MODE),
352 LOBYTE(JSY_REGISTER_SWITCH_MODE),
361static constexpr size_t JSY_REQUEST_SWITCH_MODE_LEN =
sizeof(JSY_REQUEST_SWITCH_MODE);
367static constexpr Mycila::JSY::BaudRate AUTO_DETECT_BAUD_RATES[] = {
368 Mycila::JSY::BaudRate::BAUD_4800,
369 Mycila::JSY::BaudRate::BAUD_9600,
370 Mycila::JSY::BaudRate::BAUD_19200,
371 Mycila::JSY::BaudRate::BAUD_38400,
372 Mycila::JSY::BaudRate::BAUD_1200,
373 Mycila::JSY::BaudRate::BAUD_2400,
375static constexpr size_t AUTO_DETECT_BAUD_RATES_COUNT = 6;
381static constexpr uint16_t CRCTable[] = {
646 const BaudRate baudRate,
647 const uint8_t destinationAddress,
648 const uint16_t model,
651 const uint32_t stackSize,
652 const uint32_t pause) {
656 if (GPIO_IS_VALID_GPIO(rxPin)) {
657 _pinRX = (gpio_num_t)rxPin;
659 LOGE(TAG,
"Disable JSY: Invalid Serial RX (JSY TX pin): %" PRId8, rxPin);
660 _pinRX = GPIO_NUM_NC;
664 if (GPIO_IS_VALID_OUTPUT_GPIO(txPin)) {
665 _pinTX = (gpio_num_t)txPin;
667 LOGE(TAG,
"Disable JSY: Invalid Serial TX (JSY RX pin): %" PRId8, txPin);
668 _pinTX = GPIO_NUM_NC;
672 LOGI(TAG,
"Enable JSY @ 0x%02X on Serial RX (JSY TX Pin): %" PRId8
" and Serial TX (JSY RX Pin): %" PRId8, destinationAddress, rxPin, txPin);
677 if (baudRate == BaudRate::UNKNOWN) {
678 _baudRate = _detectBauds(destinationAddress);
680 if (_baudRate == BaudRate::UNKNOWN) {
681 if (_lastAddress == MYCILA_JSY_ADDRESS_UNKNOWN)
682 LOGE(TAG,
"Unable to read any JSY @ 0x%02X at any supported speed.", destinationAddress);
684 LOGE(TAG,
"Unable to read any JSY @ 0x%02X at any supported speed but found one @ 0x%02X.", destinationAddress, _lastAddress);
691 LOGW(TAG,
"JSY @ 0x%02X bauds detection skipped, forcing baud rate: %" PRIu32, destinationAddress, _baudRate);
692 _openSerial(baudRate);
694 _baudRate = BaudRate::UNKNOWN;
695 for (
int j = 0; j < MYCILA_JSY_RETRY_COUNT; j++) {
696 if (_canRead(destinationAddress, baudRate)) {
697 _baudRate = baudRate;
702 if (_baudRate == BaudRate::UNKNOWN) {
703 LOGE(TAG,
"Unable to read any JSY @ 0x%02X at speed: %" PRIu32, destinationAddress, baudRate);
710 _model = model ? model :
readModel(destinationAddress);
712 if (_model != MYCILA_JSY_MK_1031 &&
713 _model != MYCILA_JSY_MK_163 &&
714 _model != MYCILA_JSY_MK_193 &&
715 _model != MYCILA_JSY_MK_194 &&
716 _model != MYCILA_JSY_MK_227 &&
717 _model != MYCILA_JSY_MK_229 &&
718 _model != MYCILA_JSY_MK_333) {
719 LOGE(TAG,
"Unsupported JSY model: JSY-MK-%X", _model);
726 _destinationAddress = destinationAddress;
727 LOGI(TAG,
"Detected JSY-MK-%X @ 0x%02X with speed %" PRIu32
" bauds", _model, _lastAddress, _baudRate);
729 assert(!async || xTaskCreateUniversal(_jsyTask,
"jsyTask", stackSize,
this, MYCILA_JSY_ASYNC_PRIORITY, &_taskHandle, core) == pdPASS);
734 LOGI(TAG,
"Disable JSY @ 0x%02X", _destinationAddress);
736 while (_taskHandle != NULL) {
740 std::lock_guard<std::mutex> lock(_mutex);
741 LOGD(TAG,
"Closing Serial for JSY @ 0x%02X", _destinationAddress);
744 _baudRate = BaudRate::UNKNOWN;
745 _lastAddress = MYCILA_JSY_ADDRESS_UNKNOWN;
746 _model = MYCILA_JSY_MK_UNKNOWN;
755bool Mycila::JSY::_read(
const uint8_t address, uint16_t model) {
759 std::lock_guard<std::mutex> lock(_mutex);
761#ifdef MYCILA_JSY_DEBUG
762 Serial.printf(
"[JSY] read(0x%02X)\n", address);
765 memcpy(_buffer, JSY_REQUEST_READ_REGISTERS, JSY_REQUEST_READ_REGISTERS_LEN);
769 uint16_t registerStart = 0;
770 uint16_t registerCount = 0;
771 uint8_t registerSize = 0;
774 case MYCILA_JSY_MK_1031:
775 registerSize = JSY_1031_REGISTER_LEN;
776 registerStart = JSY_1031_REGISTER_START;
777 registerCount = JSY_1031_REGISTER_COUNT;
780 case MYCILA_JSY_MK_163:
781 registerSize = JSY_163_REGISTER_LEN;
782 registerStart = JSY_163_REGISTER_START;
783 registerCount = JSY_163_REGISTER_COUNT;
786 case MYCILA_JSY_MK_193:
787 registerSize = JSY_193_REGISTER_LEN;
788 registerStart = JSY_193_REGISTER_START;
789 registerCount = JSY_193_REGISTER_COUNT;
792 case MYCILA_JSY_MK_194:
793 registerSize = JSY_194_REGISTER_LEN;
794 registerStart = JSY_194_REGISTER_START;
795 registerCount = JSY_194_REGISTER_COUNT;
798 case MYCILA_JSY_MK_227:
799 case MYCILA_JSY_MK_229:
800 registerSize = JSY_22x_REGISTER_LEN;
801 registerStart = JSY_22x_REGISTER_START;
802 registerCount = JSY_22x_REGISTER_COUNT;
805 case MYCILA_JSY_MK_333:
806 registerSize = JSY_333_REGISTER_LEN;
807 registerStart = JSY_333_REGISTER_START;
808 registerCount = JSY_333_REGISTER_COUNT;
815 _buffer[JSY_REQUEST_READ_REGISTER_ADDR_HIGH] = HIBYTE(registerStart);
816 _buffer[JSY_REQUEST_READ_REGISTER_ADDR_LOW] = LOBYTE(registerStart);
817 _buffer[JSY_REQUEST_READ_REGISTER_COUNT_HIGH] = HIBYTE(registerCount);
818 _buffer[JSY_REQUEST_READ_REGISTER_COUNT_LOW] = LOBYTE(registerCount);
820 _send(address, JSY_REQUEST_READ_REGISTERS_LEN);
821 ReadResult result = _timedRead(address, JSY_RESPONSE_SIZE_READ + registerCount * registerSize, _baudRate);
823 if (result == ReadResult::READ_TIMEOUT) {
827 _callback(EventType::EVT_READ_TIMEOUT, _data);
832 if (result == ReadResult::READ_ERROR_COUNT || result == ReadResult::READ_ERROR_CRC) {
836 _callback(EventType::EVT_READ_ERROR, _data);
841 if (result == ReadResult::READ_ERROR_ADDRESS) {
844 _callback(EventType::EVT_READ_ERROR, _data);
849 assert(result == ReadResult::READ_SUCCESS);
851 _data.address = _buffer[JSY_RESPONSE_ADDRESS];
855 case MYCILA_JSY_MK_1031: {
857 _data._metrics[0].frequency = _register16(_buffer, registerStart, registerSize, JSY_1031_REGISTER_FREQUENCY) * 0.01f;
858 _data._metrics[0].voltage = _register16(_buffer, registerStart, registerSize, JSY_1031_REGISTER_VOLTAGE) * 0.01f;
859 _data._metrics[0].current = _register32(_buffer, registerStart, registerSize, JSY_1031_REGISTER_CURRENT) * 0.0001f;
860 _data._metrics[0].activePower = _register32(_buffer, registerStart, registerSize, JSY_1031_REGISTER_ACTIVE_POWER) * 0.0001f;
861 _data._metrics[0].activeEnergy = _register32(_buffer, registerStart, registerSize, JSY_1031_REGISTER_ACTIVE_ENERGY) * 10;
862 _data._metrics[0].powerFactor = _register16(_buffer, registerStart, registerSize, JSY_1031_REGISTER_POWER_FACTOR) * 0.001f;
863 _data._metrics[0].apparentPower = _register32(_buffer, registerStart, registerSize, JSY_1031_REGISTER_APPARENT_POWER) * 0.0001f;
864 _data._metrics[0].reactivePower = _register32(_buffer, registerStart, registerSize, JSY_1031_REGISTER_REACTIVE_POWER) * 0.0001f;
867 _data.aggregate = _data._metrics[0];
872 case MYCILA_JSY_MK_163: {
876 uint8_t sign = _register8(_buffer, registerStart, registerSize, JSY_163_REGISTER_ACTIVE_POWER_SIGN, 1);
879 _data._metrics[0].frequency = _register16(_buffer, registerStart, registerSize, JSY_163_REGISTER_FREQUENCY) * 0.01f;
880 _data._metrics[0].voltage = _register16(_buffer, registerStart, registerSize, JSY_163_REGISTER_VOLTAGE) * 0.01f;
881 _data._metrics[0].current = _register16(_buffer, registerStart, registerSize, JSY_163_REGISTER_CURRENT) * 0.01f;
882 _data._metrics[0].activePower = _register16(_buffer, registerStart, registerSize, JSY_163_REGISTER_ACTIVE_POWER) * (sign ? -1.0f : 1.0f);
883 _data._metrics[0].activeEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_163_REGISTER_ACTIVE_ENERGY_IMPORTED) * 5.0f / 16.0f;
884 _data._metrics[0].powerFactor = _register16(_buffer, registerStart, registerSize, JSY_163_REGISTER_POWER_FACTOR) * 0.001f;
885 _data._metrics[0].activeEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_163_REGISTER_ACTIVE_ENERGY_RETURNED) * 5.0f / 16.0f;
889 _data._metrics[0].apparentPower = _data._metrics[0].powerFactor == 0 ? 0 : std::abs(_data._metrics[0].activePower / _data._metrics[0].powerFactor);
891 _data._metrics[0].reactivePower = std::sqrt(_data._metrics[0].apparentPower * _data._metrics[0].apparentPower - _data._metrics[0].activePower * _data._metrics[0].activePower);
893 _data._metrics[0].activeEnergy = _data._metrics[0].activeEnergyImported + _data._metrics[0].activeEnergyReturned;
896 _data.aggregate = _data._metrics[0];
901 case MYCILA_JSY_MK_193: {
903 _data._metrics[0].voltage = _register16(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH1_VOLTAGE) * 0.01f;
904 _data._metrics[0].current = _register16(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH1_CURRENT) * 0.01f;
905 _data._metrics[0].activePower = _register16(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH1_ACTIVE_POWER) * (_register16(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH1_ACTIVE_POWER_SIGN) ? -1.0f : 1.0f);
906 _data._metrics[0].activeEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH1_ACTIVE_ENERGY_POSITIVE) * 10;
907 _data._metrics[0].activeEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH1_ACTIVE_ENERGY_NEGATIVE) * 10;
908 _data._metrics[0].powerFactor = _register16(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH1_POWER_FACTOR) * 0.001f;
909 _data._metrics[0].frequency = _register16(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH1_FREQUENCY) * 0.01f;
912 _data._metrics[1].voltage = _register16(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH2_VOLTAGE) * 0.01f;
913 _data._metrics[1].current = _register16(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH2_CURRENT) * 0.01f;
914 _data._metrics[1].activePower = _register16(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH2_ACTIVE_POWER) * (_register16(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH2_ACTIVE_POWER_SIGN) ? -1.0f : 1.0f);
915 _data._metrics[1].activeEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH2_ACTIVE_ENERGY_POSITIVE) * 10;
916 _data._metrics[1].activeEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH2_ACTIVE_ENERGY_NEGATIVE) * 10;
917 _data._metrics[1].powerFactor = _register16(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH2_POWER_FACTOR) * 0.001f;
918 _data._metrics[1].frequency = _register16(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH2_FREQUENCY) * 0.01f;
922 _data._metrics[0].apparentPower = _data._metrics[0].powerFactor == 0 ? 0 : std::abs(_data._metrics[0].activePower / _data._metrics[0].powerFactor);
923 _data._metrics[1].apparentPower = _data._metrics[1].powerFactor == 0 ? 0 : std::abs(_data._metrics[1].activePower / _data._metrics[1].powerFactor);
925 _data._metrics[0].reactivePower = std::sqrt(_data._metrics[0].apparentPower * _data._metrics[0].apparentPower - _data._metrics[0].activePower * _data._metrics[0].activePower);
926 _data._metrics[1].reactivePower = std::sqrt(_data._metrics[1].apparentPower * _data._metrics[1].apparentPower - _data._metrics[1].activePower * _data._metrics[1].activePower);
928 _data._metrics[0].activeEnergy = _data._metrics[0].activeEnergyImported + _data._metrics[0].activeEnergyReturned;
929 _data._metrics[1].activeEnergy = _data._metrics[1].activeEnergyImported + _data._metrics[1].activeEnergyReturned;
932 _data.aggregate = _data._metrics[0];
933 _data.aggregate += _data._metrics[1];
934 _data.aggregate.voltage = std::max(_data._metrics[0].voltage, _data._metrics[1].voltage);
935 _data.aggregate.frequency = std::max(_data._metrics[0].frequency, _data._metrics[1].frequency);
940 case MYCILA_JSY_MK_194: {
946 uint8_t sign0 = _register8(_buffer, registerStart, registerSize, JSY_194_REGISTER_ACTIVE_POWER_SIGNS, 0);
947 uint8_t sign1 = _register8(_buffer, registerStart, registerSize, JSY_194_REGISTER_ACTIVE_POWER_SIGNS, 1);
950 float frequency = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_FREQUENCY) * 0.01f;
953 _data._metrics[0].frequency = frequency;
954 _data._metrics[0].voltage = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH1_VOLTAGE) * 0.0001f;
955 _data._metrics[0].current = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH1_CURRENT) * 0.0001f;
956 _data._metrics[0].activePower = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH1_ACTIVE_POWER) * (sign0 ? -0.0001f : 0.0001f);
957 _data._metrics[0].activeEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH1_ACTIVE_ENERGY_IMPORTED) * 0.1f;
958 _data._metrics[0].powerFactor = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH1_POWER_FACTOR) * 0.001f;
959 _data._metrics[0].activeEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH1_ACTIVE_ENERGY_RETURNED) * 0.1f;
962 _data._metrics[1].frequency = frequency;
963 _data._metrics[1].voltage = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH2_VOLTAGE) * 0.0001f;
964 _data._metrics[1].current = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH2_CURRENT) * 0.0001f;
965 _data._metrics[1].activePower = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH2_ACTIVE_POWER) * (sign1 ? -0.0001f : 0.0001f);
966 _data._metrics[1].activeEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH2_ACTIVE_ENERGY_IMPORTED) * 0.1f;
967 _data._metrics[1].powerFactor = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH2_POWER_FACTOR) * 0.001f;
968 _data._metrics[1].activeEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH2_ACTIVE_ENERGY_RETURNED) * 0.1f;
972 _data._metrics[0].apparentPower = _data._metrics[0].powerFactor == 0 ? 0 : std::abs(_data._metrics[0].activePower / _data._metrics[0].powerFactor);
973 _data._metrics[1].apparentPower = _data._metrics[1].powerFactor == 0 ? 0 : std::abs(_data._metrics[1].activePower / _data._metrics[1].powerFactor);
975 _data._metrics[0].reactivePower = std::sqrt(_data._metrics[0].apparentPower * _data._metrics[0].apparentPower - _data._metrics[0].activePower * _data._metrics[0].activePower);
976 _data._metrics[1].reactivePower = std::sqrt(_data._metrics[1].apparentPower * _data._metrics[1].apparentPower - _data._metrics[1].activePower * _data._metrics[1].activePower);
978 _data._metrics[0].activeEnergy = _data._metrics[0].activeEnergyImported + _data._metrics[0].activeEnergyReturned;
979 _data._metrics[1].activeEnergy = _data._metrics[1].activeEnergyImported + _data._metrics[1].activeEnergyReturned;
982 _data.aggregate = _data._metrics[0];
983 _data.aggregate += _data._metrics[1];
984 _data.aggregate.frequency = frequency;
985 _data.aggregate.voltage = std::max(_data._metrics[0].voltage, _data._metrics[1].voltage);
990 case MYCILA_JSY_MK_227:
991 case MYCILA_JSY_MK_229: {
993 _data._metrics[0].voltage = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_VOLTAGE) * 0.0001f;
994 _data._metrics[0].current = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_CURRENT) * 0.0001f;
995 _data._metrics[0].activePower = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_ACTIVE_POWER) * (_register16(_buffer, registerStart, registerSize, JSY_22x_REGISTER_ACTIVE_POWER_SIGN) ? -0.0001f : 0.0001f);
996 _data._metrics[0].reactivePower = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_REACTIVE_POWER) * (_register16(_buffer, registerStart, registerSize, JSY_22x_REGISTER_REACTIVE_POWER_SIGN) ? -0.0001f : 0.0001f);
997 _data._metrics[0].apparentPower = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_APPARENT_POWER) * 0.0001f;
998 _data._metrics[0].powerFactor = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_POWER_FACTOR) * 0.001f;
999 _data._metrics[0].frequency = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_FREQUENCY) * 0.01f;
1000 _data._metrics[0].activeEnergy = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_ACTIVE_ENERGY);
1001 _data._metrics[0].reactiveEnergy = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_REACTIVE_ENERGY);
1002 _data._metrics[0].activeEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_ACTIVE_ENERGY_POSITIVE);
1003 _data._metrics[0].activeEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_ACTIVE_ENERGY_NEGATIVE);
1004 _data._metrics[0].reactiveEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_REACTIVE_ENERGY_POSITIVE);
1005 _data._metrics[0].reactiveEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_REACTIVE_ENERGY_NEGATIVE);
1008 _data.aggregate = _data._metrics[0];
1013 case MYCILA_JSY_MK_333: {
1024 uint8_t sign7 = _register8(_buffer, registerStart, registerSize, JSY_333_REGISTER_POWER_SIGNS, 1) & 0x80;
1025 uint8_t sign6 = _register8(_buffer, registerStart, registerSize, JSY_333_REGISTER_POWER_SIGNS, 1) & 0x40;
1026 uint8_t sign5 = _register8(_buffer, registerStart, registerSize, JSY_333_REGISTER_POWER_SIGNS, 1) & 0x20;
1027 uint8_t sign4 = _register8(_buffer, registerStart, registerSize, JSY_333_REGISTER_POWER_SIGNS, 1) & 0x10;
1028 uint8_t sign3 = _register8(_buffer, registerStart, registerSize, JSY_333_REGISTER_POWER_SIGNS, 1) & 0x08;
1029 uint8_t sign2 = _register8(_buffer, registerStart, registerSize, JSY_333_REGISTER_POWER_SIGNS, 1) & 0x04;
1030 uint8_t sign1 = _register8(_buffer, registerStart, registerSize, JSY_333_REGISTER_POWER_SIGNS, 1) & 0x02;
1031 uint8_t sign0 = _register8(_buffer, registerStart, registerSize, JSY_333_REGISTER_POWER_SIGNS, 1) & 0x01;
1034 float frequency = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_FREQUENCY) * 0.01f;
1037 _data._metrics[0].frequency = frequency;
1038 _data._metrics[0].voltage = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_VOLTAGE) * 0.01f;
1039 _data._metrics[0].current = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_CURRENT) * 0.01f;
1040 _data._metrics[0].activePower = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_ACTIVE_POWER) * (sign0 ? -1.0f : 1.0f);
1041 _data._metrics[0].reactivePower = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_REACTIVE_POWER) * (sign4 ? -1.0f : 1.0f);
1042 _data._metrics[0].apparentPower = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_APPARENT_POWER);
1043 _data._metrics[0].powerFactor = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_POWER_FACTOR) * 0.001f;
1044 _data._metrics[0].activeEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_ACTIVE_ENERGY) * 10;
1045 _data._metrics[0].reactiveEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_REACTIVE_ENERGY) * 10;
1046 _data._metrics[0].apparentEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_APPARENT_ENERGY) * 10;
1047 _data._metrics[0].activeEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_ACTIVE_ENERGY_IMPORTED) * 10;
1048 _data._metrics[0].activeEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_ACTIVE_ENERGY_RETURNED) * 10;
1049 _data._metrics[0].reactiveEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_REACTIVE_ENERGY_IMPORTED) * 10;
1050 _data._metrics[0].reactiveEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_REACTIVE_ENERGY_RETURNED) * 10;
1051 _data._metrics[0].phaseAngleU = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_PHASE_ANGLE_U) * 0.01f;
1052 _data._metrics[0].phaseAngleI = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_PHASE_ANGLE_I) * 0.01f;
1053 _data._metrics[0].phaseAngleUI = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_PHASE_ANGLE_UI) * 0.01f;
1054 _data._metrics[0].thdU = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_THD_U) * 0.01f;
1055 _data._metrics[0].thdI = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_THD_I) * 0.01f;
1058 _data._metrics[1].frequency = frequency;
1059 _data._metrics[1].voltage = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_VOLTAGE) * 0.01f;
1060 _data._metrics[1].current = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_CURRENT) * 0.01f;
1061 _data._metrics[1].activePower = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_ACTIVE_POWER) * (sign1 ? -1.0f : 1.0f);
1062 _data._metrics[1].reactivePower = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_REACTIVE_POWER) * (sign5 ? -1.0f : 1.0f);
1063 _data._metrics[1].apparentPower = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_APPARENT_POWER);
1064 _data._metrics[1].powerFactor = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_POWER_FACTOR) * 0.001f;
1065 _data._metrics[1].activeEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_ACTIVE_ENERGY) * 0.01f;
1066 _data._metrics[1].reactiveEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_REACTIVE_ENERGY) * 10;
1067 _data._metrics[1].apparentEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_APPARENT_ENERGY) * 10;
1068 _data._metrics[1].activeEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_ACTIVE_ENERGY_IMPORTED) * 10;
1069 _data._metrics[1].activeEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_ACTIVE_ENERGY_RETURNED) * 10;
1070 _data._metrics[1].reactiveEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_REACTIVE_ENERGY_IMPORTED) * 10;
1071 _data._metrics[1].reactiveEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_REACTIVE_ENERGY_RETURNED) * 10;
1072 _data._metrics[1].phaseAngleU = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_PHASE_ANGLE_U) * 0.01f;
1073 _data._metrics[1].phaseAngleI = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_PHASE_ANGLE_I) * 0.01f;
1074 _data._metrics[1].phaseAngleUI = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_PHASE_ANGLE_UI) * 0.01f;
1075 _data._metrics[1].thdU = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_THD_U) * 0.01f;
1076 _data._metrics[1].thdI = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_THD_I) * 0.01f;
1079 _data._metrics[2].frequency = frequency;
1080 _data._metrics[2].voltage = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_VOLTAGE) * 0.01f;
1081 _data._metrics[2].current = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_CURRENT) * 0.01f;
1082 _data._metrics[2].activePower = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_ACTIVE_POWER) * (sign2 ? -1.0f : 1.0f);
1083 _data._metrics[2].reactivePower = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_REACTIVE_POWER) * (sign6 ? -1.0f : 1.0f);
1084 _data._metrics[2].apparentPower = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_APPARENT_POWER);
1085 _data._metrics[2].powerFactor = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_POWER_FACTOR) * 0.001f;
1086 _data._metrics[2].activeEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_ACTIVE_ENERGY) * 10;
1087 _data._metrics[2].reactiveEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_REACTIVE_ENERGY) * 10;
1088 _data._metrics[2].apparentEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_APPARENT_ENERGY) * 10;
1089 _data._metrics[2].activeEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_ACTIVE_ENERGY_IMPORTED) * 10;
1090 _data._metrics[2].activeEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_ACTIVE_ENERGY_RETURNED) * 10;
1091 _data._metrics[2].reactiveEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_REACTIVE_ENERGY_IMPORTED) * 10;
1092 _data._metrics[2].reactiveEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_REACTIVE_ENERGY_RETURNED) * 10;
1093 _data._metrics[2].phaseAngleU = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_PHASE_ANGLE_U) * 0.01f;
1094 _data._metrics[2].phaseAngleI = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_PHASE_ANGLE_I) * 0.01f;
1095 _data._metrics[2].phaseAngleUI = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_PHASE_ANGLE_UI) * 0.01f;
1096 _data._metrics[2].thdU = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_THD_U) * 0.01f;
1097 _data._metrics[2].thdI = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_THD_I) * 0.01f;
1100 _data.aggregate.frequency = frequency;
1101 _data.aggregate.activePower = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_ACTIVE_POWER) * (sign3 ? -1.0f : 1.0f);
1102 _data.aggregate.reactivePower = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_REACTIVE_POWER) * (sign7 ? -1.0f : 1.0f);
1103 _data.aggregate.apparentPower = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_APPARENT_POWER);
1104 _data.aggregate.powerFactor = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_POWER_FACTOR) * 0.001f;
1105 _data.aggregate.activeEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_ACTIVE_ENERGY) * 10;
1106 _data.aggregate.reactiveEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_REACTIVE_ENERGY) * 10;
1107 _data.aggregate.apparentEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_APPARENT_ENERGY) * 10;
1108 _data.aggregate.activeEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_ACTIVE_ENERGY_IMPORTED) * 10;
1109 _data.aggregate.activeEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_ACTIVE_ENERGY_RETURNED) * 10;
1110 _data.aggregate.reactiveEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_REACTIVE_ENERGY_IMPORTED) * 10;
1111 _data.aggregate.reactiveEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_REACTIVE_ENERGY_RETURNED) * 10;
1112 _data.aggregate.current = _data._metrics[0].current + _data._metrics[1].current + _data._metrics[2].current;
1113 _data.aggregate.voltage = _data.aggregate.current == 0 ? NAN : _data.aggregate.apparentPower / _data.aggregate.current;
1125 _callback(EventType::EVT_READ, _data);
1137 return MYCILA_JSY_MK_UNKNOWN;
1139 LOGD(TAG,
"readModel(0x%02X)", address);
1141 std::lock_guard<std::mutex> lock(_mutex);
1143#ifdef MYCILA_JSY_DEBUG
1144 Serial.printf(
"[JSY] readModel(0x%02X)\n", address);
1147 memcpy(_buffer, JSY_REQUEST_READ_MODEL, JSY_REQUEST_READ_MODEL_LEN);
1148 _send(address, JSY_REQUEST_READ_MODEL_LEN);
1149 ReadResult result = _timedRead(address, JSY_RESPONSE_SIZE_READ_MODEL, _baudRate);
1151 if (result != ReadResult::READ_SUCCESS) {
1152 return MYCILA_JSY_MK_UNKNOWN;
1155 return (_buffer[JSY_RESPONSE_DATA] << 8) + _buffer[JSY_RESPONSE_DATA + 1];
1162Mycila::JSY::Mode Mycila::JSY::_readMode(
const uint8_t address,
const uint16_t model) {
1164 return Mode::UNKNOWN;
1167 case MYCILA_JSY_MK_163:
1168 case MYCILA_JSY_MK_193:
1169 case MYCILA_JSY_MK_194:
1170 case MYCILA_JSY_MK_333:
1172 case MYCILA_JSY_MK_227:
1173 case MYCILA_JSY_MK_229:
1175 case MYCILA_JSY_MK_1031:
1178 return Mode::UNKNOWN;
1181 LOGD(TAG,
"readMode(0x%02X)", address);
1183 std::lock_guard<std::mutex> lock(_mutex);
1185#ifdef MYCILA_JSY_DEBUG
1186 Serial.printf(
"[JSY] readMode(0x%02X)\n", address);
1189 memcpy(_buffer, JSY_REQUEST_READ_MODE, JSY_REQUEST_READ_MODE_LEN);
1190 _send(address, JSY_REQUEST_READ_MODE_LEN);
1191 ReadResult result = _timedRead(address, JSY_RESPONSE_SIZE_READ_MODE, _baudRate);
1193 if (result != ReadResult::READ_SUCCESS) {
1194 return Mode::UNKNOWN;
1197 switch (_buffer[JSY_RESPONSE_DATA]) {
1203 return Mode::UNKNOWN;
1207bool Mycila::JSY::_setMode(
const uint8_t address,
const uint16_t model,
const Mode mode) {
1211 if (mode == Mode::UNKNOWN)
1215 case MYCILA_JSY_MK_163:
1216 case MYCILA_JSY_MK_193:
1217 case MYCILA_JSY_MK_194:
1218 case MYCILA_JSY_MK_333:
1219 return mode == Mode::AC;
1220 case MYCILA_JSY_MK_227:
1221 case MYCILA_JSY_MK_229:
1222 return mode == Mode::DC;
1223 case MYCILA_JSY_MK_1031:
1229 LOGD(TAG,
"setMode(0x%02X) mode=%s", address, mode == Mode::AC ?
"AC" :
"DC");
1231 std::lock_guard<std::mutex> lock(_mutex);
1233#ifdef MYCILA_JSY_DEBUG
1234 Serial.printf(
"[JSY] setMode(0x%02X, %s)\n", address, mode == Mode::AC ?
"AC" :
"DC");
1237 memcpy(_buffer, JSY_REQUEST_SWITCH_MODE, JSY_REQUEST_SWITCH_MODE_LEN);
1239 _buffer[JSY_REQUEST_SET_MODE] = mode == Mode::AC ? JSY_MODE_AC : JSY_MODE_DC;
1241 _send(address, JSY_REQUEST_SWITCH_MODE_LEN);
1242 ReadResult result = _timedRead(address, JSY_RESPONSE_SIZE_SWITCH_MODE, _baudRate);
1244 return result == ReadResult::READ_SUCCESS;
1255 LOGD(TAG,
"resetEnergy(0x%02X)", address);
1257 std::lock_guard<std::mutex> lock(_mutex);
1259#ifdef MYCILA_JSY_DEBUG
1260 Serial.printf(
"[JSY] resetEnergy(0x%02X)\n", address);
1263 memcpy(_buffer, JSY_REQUEST_RESET_ENERGY, JSY_REQUEST_RESET_ENERGY_LEN);
1264 _send(address, JSY_REQUEST_RESET_ENERGY_LEN);
1265 ReadResult result = _timedRead(address, JSY_RESPONSE_SIZE_RESET_ENERGY, _baudRate);
1267 return result == ReadResult::READ_SUCCESS;
1274Mycila::JSY::BaudRate Mycila::JSY::getMinAvailableBaudRate()
const {
1276 return BaudRate::UNKNOWN;
1277 return getMinAvailableBaudRate(_model);
1280Mycila::JSY::BaudRate Mycila::JSY::getMinAvailableBaudRate(uint16_t model) {
1282 case MYCILA_JSY_MK_163:
1283 case MYCILA_JSY_MK_193:
1284 case MYCILA_JSY_MK_194:
1285 case MYCILA_JSY_MK_227:
1286 case MYCILA_JSY_MK_229:
1287 return BaudRate::BAUD_1200;
1288 return BaudRate::BAUD_1200;
1289 case MYCILA_JSY_MK_1031:
1290 case MYCILA_JSY_MK_333:
1291 return BaudRate::BAUD_4800;
1293 return BaudRate::UNKNOWN;
1299 return BaudRate::UNKNOWN;
1305 case MYCILA_JSY_MK_163:
1306 case MYCILA_JSY_MK_227:
1307 case MYCILA_JSY_MK_229:
1308 return BaudRate::BAUD_9600;
1309 case MYCILA_JSY_MK_1031:
1310 case MYCILA_JSY_MK_333:
1311 return BaudRate::BAUD_19200;
1312 case MYCILA_JSY_MK_193:
1313 case MYCILA_JSY_MK_194:
1314 return BaudRate::BAUD_38400;
1316 return BaudRate::UNKNOWN;
1327 return getMinAvailableBaudRate(model) <= baudRate && baudRate <= getMaxAvailableBaudRate(model);
1331 return _set(address, address ? address : (_lastAddress ? _lastAddress : MYCILA_JSY_ADDRESS_DEFAULT), baudRate);
1335 return _set(address, newAddress, _baudRate);
1338bool Mycila::JSY::_set(
const uint8_t address,
const uint8_t newAddress,
const BaudRate newBaudRate) {
1342 if (newBaudRate == BaudRate::UNKNOWN)
1345 if (newAddress == MYCILA_JSY_ADDRESS_UNKNOWN)
1348 LOGD(TAG,
"set(0x%02X) address=0x%02X, bauds=%" PRIu32, address, newAddress, newBaudRate);
1350 std::lock_guard<std::mutex> lock(_mutex);
1352#ifdef MYCILA_JSY_DEBUG
1353 Serial.printf(
"[JSY] _set(0x%02X)\n", address);
1356 memcpy(_buffer, JSY_REQUEST_SET_COM, JSY_REQUEST_SET_COM_LEN);
1359 _buffer[JSY_REQUEST_SET_ADDRESS] = newAddress;
1362 switch (newBaudRate) {
1363 case BaudRate::BAUD_1200:
1364 _buffer[JSY_REQUEST_SET_BAUDS] = 0x03;
1366 case BaudRate::BAUD_2400:
1367 _buffer[JSY_REQUEST_SET_BAUDS] = 0x04;
1369 case BaudRate::BAUD_4800:
1370 _buffer[JSY_REQUEST_SET_BAUDS] = 0x05;
1372 case BaudRate::BAUD_9600:
1373 _buffer[JSY_REQUEST_SET_BAUDS] = 0x06;
1375 case BaudRate::BAUD_19200:
1376 _buffer[JSY_REQUEST_SET_BAUDS] = 0x07;
1378 case BaudRate::BAUD_38400:
1379 _buffer[JSY_REQUEST_SET_BAUDS] = 0x08;
1386 _send(address, JSY_REQUEST_SET_COM_LEN);
1387 ReadResult result = _timedRead(address, JSY_RESPONSE_SIZE_SET_COM, _baudRate);
1390 if (result != ReadResult::READ_SUCCESS && result != ReadResult::READ_ERROR_ADDRESS) {
1395 if (result == ReadResult::READ_ERROR_ADDRESS && _lastAddress != newAddress) {
1399 _openSerial(newBaudRate);
1401 bool success =
false;
1402 for (
int i = 0; i < MYCILA_JSY_RETRY_COUNT; i++) {
1403 if (_canRead(address, newBaudRate)) {
1411 _baudRate = newBaudRate;
1414 if (_destinationAddress != MYCILA_JSY_ADDRESS_BROADCAST && _destinationAddress == address) {
1415 _destinationAddress = newAddress;
1419 LOGE(TAG,
"Unable to read JSY @ 0x%02X at speed: %" PRIu32, address, newBaudRate);
1420 if (_baudRate != BaudRate::UNKNOWN) {
1421 _openSerial(_baudRate);
1432#ifdef MYCILA_JSON_SUPPORT
1433void Mycila::JSY::toJson(
const JsonObject& root)
const {
1434 root[
"enabled"] = _enabled;
1435 root[
"time"] = _time;
1436 root[
"speed"] = _baudRate;
1445bool Mycila::JSY::_canRead(
const uint8_t address, BaudRate baudRate) {
1446#ifdef MYCILA_JSY_DEBUG
1447 Serial.printf(
"[JSY] _canRead(0x%02X)\n", address);
1449 memcpy(_buffer, JSY_REQUEST_READ_MODEL, JSY_REQUEST_READ_MODEL_LEN);
1450 _send(address, JSY_REQUEST_READ_MODEL_LEN);
1451 return _timedRead(address, JSY_RESPONSE_SIZE_READ_MODEL, baudRate) == ReadResult::READ_SUCCESS;
1454Mycila::JSY::ReadResult Mycila::JSY::_timedRead(
const uint8_t expectedAddress,
const size_t expectedLen,
const BaudRate baudRate) {
1456 while (count < expectedLen) {
1457 size_t read = _serial->readBytes(_buffer + count, expectedLen - count);
1465#ifdef MYCILA_JSY_DEBUG
1466 Serial.printf(
"[JSY] timedRead(0x%02X) %d < ", expectedAddress, count);
1467 for (
size_t i = 0; i < count; i++) {
1468 Serial.printf(
"0x%02X ", _buffer[i]);
1477 LOGD(TAG,
"timedRead(0x%02X) timeout", expectedAddress);
1478 return ReadResult::READ_TIMEOUT;
1482 if (count != expectedLen) {
1483 LOGD(TAG,
"timedRead(0x%02X) error: len %d != %d", expectedAddress, count, expectedLen);
1484 return ReadResult::READ_ERROR_COUNT;
1488 uint16_t crc = _crc16(_buffer, expectedLen - 2);
1489 if (_buffer[expectedLen - 2] != LOBYTE(crc) || _buffer[expectedLen - 1] != HIBYTE(crc)) {
1490 LOGD(TAG,
"timedRead(0x%02X) error: bad CRC 0x%02X 0x%02X != 0x%02X 0x%02X", expectedAddress, _buffer[expectedLen - 2], _buffer[expectedLen - 1], LOBYTE(crc), HIBYTE(crc));
1491 return ReadResult::READ_ERROR_CRC;
1494 _lastAddress = _buffer[JSY_RESPONSE_ADDRESS];
1497 if (expectedAddress != MYCILA_JSY_ADDRESS_BROADCAST && expectedAddress != _lastAddress) {
1498 LOGD(TAG,
"timedRead(0x%02X) error: wrong device address 0x%02X", expectedAddress, _lastAddress);
1499 return ReadResult::READ_ERROR_ADDRESS;
1502 return ReadResult::READ_SUCCESS;
1505void Mycila::JSY::_send(
const uint8_t address,
const size_t len) {
1507 _buffer[JSY_REQUEST_ADDRESS] = address;
1510 uint16_t crc = _crc16(_buffer, len - 2);
1511 _buffer[len - 2] = LOBYTE(crc);
1512 _buffer[len - 1] = HIBYTE(crc);
1514#ifdef MYCILA_JSY_DEBUG
1515 Serial.printf(
"[JSY] send(0x%02X) %d > ", address, len);
1516 for (
size_t i = 0; i < len; i++) {
1517 Serial.printf(
"0x%02X ", _buffer[i]);
1522 _serial->flush(
false);
1523 _serial->write(_buffer, len);
1526size_t Mycila::JSY::_drop() {
1528 if (_serial->available()) {
1529#ifdef MYCILA_JSY_DEBUG
1530 Serial.printf(
"[JSY] drop < ");
1532 while (_serial->available()) {
1533#ifdef MYCILA_JSY_DEBUG
1534 Serial.printf(
"0x%02X ", _serial->read());
1540#ifdef MYCILA_JSY_DEBUG
1547void Mycila::JSY::_openSerial(BaudRate baudRate) {
1548 LOGD(TAG,
"openSerial(%" PRIu32
")", baudRate);
1549 _serial->begin(baudRate, SERIAL_8N1, _pinRX, _pinTX);
1550 _serial->setTimeout(MYCILA_JSY_READ_TIMEOUT_MS);
1553 while (!_serial->availableForWrite())
1556 _serial->flush(
false);
1559Mycila::JSY::BaudRate Mycila::JSY::_detectBauds(
const uint8_t address) {
1560 for (
int i = 0; i < AUTO_DETECT_BAUD_RATES_COUNT * 2; i++) {
1561 BaudRate baudRate = AUTO_DETECT_BAUD_RATES[i % AUTO_DETECT_BAUD_RATES_COUNT];
1562 LOGD(TAG,
"find(0x%02X) %" PRIu32
" bauds", address, baudRate);
1563 _openSerial(baudRate);
1564 for (
int j = 0; j < MYCILA_JSY_RETRY_COUNT; j++) {
1565 if (_canRead(address, baudRate)) {
1570 return BaudRate::UNKNOWN;
1579inline uint16_t Mycila::JSY::_crc16(
const uint8_t* data,
size_t len) {
1580 uint16_t crc = 0xFFFF;
1582 uint8_t temp = *(data++) ^ LOBYTE(crc);
1583 crc = (crc >> 8) ^ pgm_read_word_near(CRCTable + temp);
1588uint8_t Mycila::JSY::_register8(
const uint8_t* buffer,
const uint16_t registerStart,
const uint16_t registerSize,
const uint16_t registerAddress, uint8_t index) {
1589 return buffer[JSY_RESPONSE_DATA + (registerAddress - registerStart) * registerSize + index];
1592uint16_t Mycila::JSY::_register16(
const uint8_t* buffer,
const uint16_t registerStart,
const uint16_t registerSize,
const uint16_t registerAddress) {
1593 const size_t start = JSY_RESPONSE_DATA + (registerAddress - registerStart) * registerSize;
1594 return (buffer[start] << 8) + buffer[start + 1];
1597uint32_t Mycila::JSY::_register32(
const uint8_t* buffer,
const uint16_t registerStart,
const uint16_t registerSize,
const uint16_t registerAddress) {
1598 const size_t start = JSY_RESPONSE_DATA + (registerAddress - registerStart) * registerSize;
1599 return (buffer[start] << 24) +
1600 (buffer[start + 1] << 16) +
1601 (buffer[start + 2] << 8) +
1602 (buffer[start + 3]);
1605const char* Mycila::JSY::getModelName(uint16_t model) {
1607 case MYCILA_JSY_MK_1031:
1608 return MYCILA_JSY_MK_1031_NAME;
1609 case MYCILA_JSY_MK_163:
1610 return MYCILA_JSY_MK_163_NAME;
1611 case MYCILA_JSY_MK_193:
1612 return MYCILA_JSY_MK_193_NAME;
1613 case MYCILA_JSY_MK_194:
1614 return MYCILA_JSY_MK_194_NAME;
1615 case MYCILA_JSY_MK_227:
1616 return MYCILA_JSY_MK_227_NAME;
1617 case MYCILA_JSY_MK_229:
1618 return MYCILA_JSY_MK_229_NAME;
1619 case MYCILA_JSY_MK_333:
1620 return MYCILA_JSY_MK_333_NAME;
1622 return emptyString.c_str();
1626void Mycila::JSY::_jsyTask(
void* params) {
1627 JSY* jsy =
reinterpret_cast<JSY*
>(params);
1628 while (jsy->_enabled) {
1630 if (jsy->_pause > 0) {
1635 }
else if (jsy->_pause > 0) {
1641 jsy->_taskHandle = NULL;
bool read()
Read the JSY values.
void begin(HardwareSerial &serial, int8_t rxPin, int8_t txPin, bool async, uint8_t core=MYCILA_JSY_ASYNC_CORE, uint32_t stackSize=MYCILA_JSY_ASYNC_STACK_SIZE, uint32_t pause=MYCILA_JSY_ASYNC_READ_PAUSE_MS)
Initialize the JSY with the given RX and TX pins.
bool setDeviceAddress(uint8_t newAddress)
Set a new address for a device.
bool resetEnergy()
Reset the energy counters of the JSY.
bool setBaudRate(BaudRate baudRate)
Change the baud rate of the JSY.
BaudRate getMaxAvailableBaudRate() const
Get the maximum available baud rate supported by the current JSY model connected.
bool isBaudRateSupported(BaudRate baudRate) const
Check if a baud rate is supported by the current JSY model connected.
void end()
Ends the JSY communication.
uint16_t readModel()
Reads the JSY model.