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 _baudRate = BaudRate::UNKNOWN;
741 _lastAddress = MYCILA_JSY_ADDRESS_UNKNOWN;
742 _model = MYCILA_JSY_MK_UNKNOWN;
752bool Mycila::JSY::_read(
const uint8_t address, uint16_t model) {
756 std::lock_guard<std::mutex> lock(_mutex);
758#ifdef MYCILA_JSY_DEBUG
759 Serial.printf(
"[JSY] read(0x%02X)\n", address);
762 memcpy(_buffer, JSY_REQUEST_READ_REGISTERS, JSY_REQUEST_READ_REGISTERS_LEN);
766 uint16_t registerStart = 0;
767 uint16_t registerCount = 0;
768 uint8_t registerSize = 0;
771 case MYCILA_JSY_MK_1031:
772 registerSize = JSY_1031_REGISTER_LEN;
773 registerStart = JSY_1031_REGISTER_START;
774 registerCount = JSY_1031_REGISTER_COUNT;
777 case MYCILA_JSY_MK_163:
778 registerSize = JSY_163_REGISTER_LEN;
779 registerStart = JSY_163_REGISTER_START;
780 registerCount = JSY_163_REGISTER_COUNT;
783 case MYCILA_JSY_MK_193:
784 registerSize = JSY_193_REGISTER_LEN;
785 registerStart = JSY_193_REGISTER_START;
786 registerCount = JSY_193_REGISTER_COUNT;
789 case MYCILA_JSY_MK_194:
790 registerSize = JSY_194_REGISTER_LEN;
791 registerStart = JSY_194_REGISTER_START;
792 registerCount = JSY_194_REGISTER_COUNT;
795 case MYCILA_JSY_MK_227:
796 case MYCILA_JSY_MK_229:
797 registerSize = JSY_22x_REGISTER_LEN;
798 registerStart = JSY_22x_REGISTER_START;
799 registerCount = JSY_22x_REGISTER_COUNT;
802 case MYCILA_JSY_MK_333:
803 registerSize = JSY_333_REGISTER_LEN;
804 registerStart = JSY_333_REGISTER_START;
805 registerCount = JSY_333_REGISTER_COUNT;
812 _buffer[JSY_REQUEST_READ_REGISTER_ADDR_HIGH] = HIBYTE(registerStart);
813 _buffer[JSY_REQUEST_READ_REGISTER_ADDR_LOW] = LOBYTE(registerStart);
814 _buffer[JSY_REQUEST_READ_REGISTER_COUNT_HIGH] = HIBYTE(registerCount);
815 _buffer[JSY_REQUEST_READ_REGISTER_COUNT_LOW] = LOBYTE(registerCount);
817 _send(address, JSY_REQUEST_READ_REGISTERS_LEN);
818 ReadResult result = _timedRead(address, JSY_RESPONSE_SIZE_READ + registerCount * registerSize, _baudRate);
820 if (result == ReadResult::READ_TIMEOUT) {
824 _callback(EventType::EVT_READ_TIMEOUT, _data);
829 if (result == ReadResult::READ_ERROR_COUNT || result == ReadResult::READ_ERROR_CRC) {
833 _callback(EventType::EVT_READ_ERROR, _data);
838 if (result == ReadResult::READ_ERROR_ADDRESS) {
841 _callback(EventType::EVT_READ_ERROR, _data);
846 assert(result == ReadResult::READ_SUCCESS);
848 _data.address = _buffer[JSY_RESPONSE_ADDRESS];
852 case MYCILA_JSY_MK_1031: {
854 _data._metrics[0].frequency = _register16(_buffer, registerStart, registerSize, JSY_1031_REGISTER_FREQUENCY) * 0.01f;
855 _data._metrics[0].voltage = _register16(_buffer, registerStart, registerSize, JSY_1031_REGISTER_VOLTAGE) * 0.01f;
856 _data._metrics[0].current = _register32(_buffer, registerStart, registerSize, JSY_1031_REGISTER_CURRENT) * 0.0001f;
857 _data._metrics[0].activePower = _register32(_buffer, registerStart, registerSize, JSY_1031_REGISTER_ACTIVE_POWER) * 0.0001f;
858 _data._metrics[0].activeEnergy = _register32(_buffer, registerStart, registerSize, JSY_1031_REGISTER_ACTIVE_ENERGY) * 10;
859 _data._metrics[0].powerFactor = _register16(_buffer, registerStart, registerSize, JSY_1031_REGISTER_POWER_FACTOR) * 0.001f;
860 _data._metrics[0].apparentPower = _register32(_buffer, registerStart, registerSize, JSY_1031_REGISTER_APPARENT_POWER) * 0.0001f;
861 _data._metrics[0].reactivePower = _register32(_buffer, registerStart, registerSize, JSY_1031_REGISTER_REACTIVE_POWER) * 0.0001f;
864 _data.aggregate = _data._metrics[0];
869 case MYCILA_JSY_MK_163: {
873 uint8_t sign = _register8(_buffer, registerStart, registerSize, JSY_163_REGISTER_ACTIVE_POWER_SIGN, 1);
876 _data._metrics[0].frequency = _register16(_buffer, registerStart, registerSize, JSY_163_REGISTER_FREQUENCY) * 0.01f;
877 _data._metrics[0].voltage = _register16(_buffer, registerStart, registerSize, JSY_163_REGISTER_VOLTAGE) * 0.01f;
878 _data._metrics[0].current = _register16(_buffer, registerStart, registerSize, JSY_163_REGISTER_CURRENT) * 0.01f;
879 _data._metrics[0].activePower = _register16(_buffer, registerStart, registerSize, JSY_163_REGISTER_ACTIVE_POWER) * (sign ? -1.0f : 1.0f);
880 _data._metrics[0].activeEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_163_REGISTER_ACTIVE_ENERGY_IMPORTED) * 5.0f / 16.0f;
881 _data._metrics[0].powerFactor = _register16(_buffer, registerStart, registerSize, JSY_163_REGISTER_POWER_FACTOR) * 0.001f;
882 _data._metrics[0].activeEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_163_REGISTER_ACTIVE_ENERGY_RETURNED) * 5.0f / 16.0f;
886 _data._metrics[0].apparentPower = _data._metrics[0].powerFactor == 0 ? 0 : std::abs(_data._metrics[0].activePower / _data._metrics[0].powerFactor);
888 _data._metrics[0].reactivePower = std::sqrt(_data._metrics[0].apparentPower * _data._metrics[0].apparentPower - _data._metrics[0].activePower * _data._metrics[0].activePower);
890 _data._metrics[0].activeEnergy = _data._metrics[0].activeEnergyImported + _data._metrics[0].activeEnergyReturned;
893 _data.aggregate = _data._metrics[0];
898 case MYCILA_JSY_MK_193: {
900 _data._metrics[0].voltage = _register16(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH1_VOLTAGE) * 0.01f;
901 _data._metrics[0].current = _register16(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH1_CURRENT) * 0.01f;
902 _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);
903 _data._metrics[0].activeEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH1_ACTIVE_ENERGY_POSITIVE) * 10;
904 _data._metrics[0].activeEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH1_ACTIVE_ENERGY_NEGATIVE) * 10;
905 _data._metrics[0].powerFactor = _register16(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH1_POWER_FACTOR) * 0.001f;
906 _data._metrics[0].frequency = _register16(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH1_FREQUENCY) * 0.01f;
909 _data._metrics[1].voltage = _register16(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH2_VOLTAGE) * 0.01f;
910 _data._metrics[1].current = _register16(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH2_CURRENT) * 0.01f;
911 _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);
912 _data._metrics[1].activeEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH2_ACTIVE_ENERGY_POSITIVE) * 10;
913 _data._metrics[1].activeEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH2_ACTIVE_ENERGY_NEGATIVE) * 10;
914 _data._metrics[1].powerFactor = _register16(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH2_POWER_FACTOR) * 0.001f;
915 _data._metrics[1].frequency = _register16(_buffer, registerStart, registerSize, JSY_193_REGISTER_CH2_FREQUENCY) * 0.01f;
919 _data._metrics[0].apparentPower = _data._metrics[0].powerFactor == 0 ? 0 : std::abs(_data._metrics[0].activePower / _data._metrics[0].powerFactor);
920 _data._metrics[1].apparentPower = _data._metrics[1].powerFactor == 0 ? 0 : std::abs(_data._metrics[1].activePower / _data._metrics[1].powerFactor);
922 _data._metrics[0].reactivePower = std::sqrt(_data._metrics[0].apparentPower * _data._metrics[0].apparentPower - _data._metrics[0].activePower * _data._metrics[0].activePower);
923 _data._metrics[1].reactivePower = std::sqrt(_data._metrics[1].apparentPower * _data._metrics[1].apparentPower - _data._metrics[1].activePower * _data._metrics[1].activePower);
925 _data._metrics[0].activeEnergy = _data._metrics[0].activeEnergyImported + _data._metrics[0].activeEnergyReturned;
926 _data._metrics[1].activeEnergy = _data._metrics[1].activeEnergyImported + _data._metrics[1].activeEnergyReturned;
929 _data.aggregate = _data._metrics[0];
930 _data.aggregate += _data._metrics[1];
931 _data.aggregate.voltage = std::max(_data._metrics[0].voltage, _data._metrics[1].voltage);
932 _data.aggregate.frequency = std::max(_data._metrics[0].frequency, _data._metrics[1].frequency);
937 case MYCILA_JSY_MK_194: {
943 uint8_t sign0 = _register8(_buffer, registerStart, registerSize, JSY_194_REGISTER_ACTIVE_POWER_SIGNS, 0);
944 uint8_t sign1 = _register8(_buffer, registerStart, registerSize, JSY_194_REGISTER_ACTIVE_POWER_SIGNS, 1);
947 float frequency = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_FREQUENCY) * 0.01f;
950 _data._metrics[0].frequency = frequency;
951 _data._metrics[0].voltage = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH1_VOLTAGE) * 0.0001f;
952 _data._metrics[0].current = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH1_CURRENT) * 0.0001f;
953 _data._metrics[0].activePower = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH1_ACTIVE_POWER) * (sign0 ? -0.0001f : 0.0001f);
954 _data._metrics[0].activeEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH1_ACTIVE_ENERGY_IMPORTED) * 0.1f;
955 _data._metrics[0].powerFactor = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH1_POWER_FACTOR) * 0.001f;
956 _data._metrics[0].activeEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH1_ACTIVE_ENERGY_RETURNED) * 0.1f;
959 _data._metrics[1].frequency = frequency;
960 _data._metrics[1].voltage = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH2_VOLTAGE) * 0.0001f;
961 _data._metrics[1].current = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH2_CURRENT) * 0.0001f;
962 _data._metrics[1].activePower = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH2_ACTIVE_POWER) * (sign1 ? -0.0001f : 0.0001f);
963 _data._metrics[1].activeEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH2_ACTIVE_ENERGY_IMPORTED) * 0.1f;
964 _data._metrics[1].powerFactor = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH2_POWER_FACTOR) * 0.001f;
965 _data._metrics[1].activeEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_194_REGISTER_CH2_ACTIVE_ENERGY_RETURNED) * 0.1f;
969 _data._metrics[0].apparentPower = _data._metrics[0].powerFactor == 0 ? 0 : std::abs(_data._metrics[0].activePower / _data._metrics[0].powerFactor);
970 _data._metrics[1].apparentPower = _data._metrics[1].powerFactor == 0 ? 0 : std::abs(_data._metrics[1].activePower / _data._metrics[1].powerFactor);
972 _data._metrics[0].reactivePower = std::sqrt(_data._metrics[0].apparentPower * _data._metrics[0].apparentPower - _data._metrics[0].activePower * _data._metrics[0].activePower);
973 _data._metrics[1].reactivePower = std::sqrt(_data._metrics[1].apparentPower * _data._metrics[1].apparentPower - _data._metrics[1].activePower * _data._metrics[1].activePower);
975 _data._metrics[0].activeEnergy = _data._metrics[0].activeEnergyImported + _data._metrics[0].activeEnergyReturned;
976 _data._metrics[1].activeEnergy = _data._metrics[1].activeEnergyImported + _data._metrics[1].activeEnergyReturned;
979 _data.aggregate = _data._metrics[0];
980 _data.aggregate += _data._metrics[1];
981 _data.aggregate.frequency = frequency;
982 _data.aggregate.voltage = std::max(_data._metrics[0].voltage, _data._metrics[1].voltage);
987 case MYCILA_JSY_MK_227:
988 case MYCILA_JSY_MK_229: {
990 _data._metrics[0].voltage = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_VOLTAGE) * 0.0001f;
991 _data._metrics[0].current = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_CURRENT) * 0.0001f;
992 _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);
993 _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);
994 _data._metrics[0].apparentPower = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_APPARENT_POWER) * 0.0001f;
995 _data._metrics[0].powerFactor = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_POWER_FACTOR) * 0.001f;
996 _data._metrics[0].frequency = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_FREQUENCY) * 0.01f;
997 _data._metrics[0].activeEnergy = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_ACTIVE_ENERGY);
998 _data._metrics[0].reactiveEnergy = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_REACTIVE_ENERGY);
999 _data._metrics[0].activeEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_ACTIVE_ENERGY_POSITIVE);
1000 _data._metrics[0].activeEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_ACTIVE_ENERGY_NEGATIVE);
1001 _data._metrics[0].reactiveEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_REACTIVE_ENERGY_POSITIVE);
1002 _data._metrics[0].reactiveEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_22x_REGISTER_REACTIVE_ENERGY_NEGATIVE);
1005 _data.aggregate = _data._metrics[0];
1010 case MYCILA_JSY_MK_333: {
1021 uint8_t sign7 = _register8(_buffer, registerStart, registerSize, JSY_333_REGISTER_POWER_SIGNS, 1) & 0x80;
1022 uint8_t sign6 = _register8(_buffer, registerStart, registerSize, JSY_333_REGISTER_POWER_SIGNS, 1) & 0x40;
1023 uint8_t sign5 = _register8(_buffer, registerStart, registerSize, JSY_333_REGISTER_POWER_SIGNS, 1) & 0x20;
1024 uint8_t sign4 = _register8(_buffer, registerStart, registerSize, JSY_333_REGISTER_POWER_SIGNS, 1) & 0x10;
1025 uint8_t sign3 = _register8(_buffer, registerStart, registerSize, JSY_333_REGISTER_POWER_SIGNS, 1) & 0x08;
1026 uint8_t sign2 = _register8(_buffer, registerStart, registerSize, JSY_333_REGISTER_POWER_SIGNS, 1) & 0x04;
1027 uint8_t sign1 = _register8(_buffer, registerStart, registerSize, JSY_333_REGISTER_POWER_SIGNS, 1) & 0x02;
1028 uint8_t sign0 = _register8(_buffer, registerStart, registerSize, JSY_333_REGISTER_POWER_SIGNS, 1) & 0x01;
1031 float frequency = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_FREQUENCY) * 0.01f;
1034 _data._metrics[0].frequency = frequency;
1035 _data._metrics[0].voltage = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_VOLTAGE) * 0.01f;
1036 _data._metrics[0].current = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_CURRENT) * 0.01f;
1037 _data._metrics[0].activePower = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_ACTIVE_POWER) * (sign0 ? -1.0f : 1.0f);
1038 _data._metrics[0].reactivePower = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_REACTIVE_POWER) * (sign4 ? -1.0f : 1.0f);
1039 _data._metrics[0].apparentPower = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_APPARENT_POWER);
1040 _data._metrics[0].powerFactor = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_POWER_FACTOR) * 0.001f;
1041 _data._metrics[0].activeEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_ACTIVE_ENERGY) * 10;
1042 _data._metrics[0].reactiveEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_REACTIVE_ENERGY) * 10;
1043 _data._metrics[0].apparentEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_APPARENT_ENERGY) * 10;
1044 _data._metrics[0].activeEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_ACTIVE_ENERGY_IMPORTED) * 10;
1045 _data._metrics[0].activeEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_ACTIVE_ENERGY_RETURNED) * 10;
1046 _data._metrics[0].reactiveEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_REACTIVE_ENERGY_IMPORTED) * 10;
1047 _data._metrics[0].reactiveEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_REACTIVE_ENERGY_RETURNED) * 10;
1048 _data._metrics[0].phaseAngleU = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_PHASE_ANGLE_U) * 0.01f;
1049 _data._metrics[0].phaseAngleI = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_PHASE_ANGLE_I) * 0.01f;
1050 _data._metrics[0].phaseAngleUI = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_PHASE_ANGLE_UI) * 0.01f;
1051 _data._metrics[0].thdU = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_THD_U) * 0.01f;
1052 _data._metrics[0].thdI = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_A_THD_I) * 0.01f;
1055 _data._metrics[1].frequency = frequency;
1056 _data._metrics[1].voltage = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_VOLTAGE) * 0.01f;
1057 _data._metrics[1].current = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_CURRENT) * 0.01f;
1058 _data._metrics[1].activePower = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_ACTIVE_POWER) * (sign1 ? -1.0f : 1.0f);
1059 _data._metrics[1].reactivePower = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_REACTIVE_POWER) * (sign5 ? -1.0f : 1.0f);
1060 _data._metrics[1].apparentPower = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_APPARENT_POWER);
1061 _data._metrics[1].powerFactor = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_POWER_FACTOR) * 0.001f;
1062 _data._metrics[1].activeEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_ACTIVE_ENERGY) * 0.01f;
1063 _data._metrics[1].reactiveEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_REACTIVE_ENERGY) * 10;
1064 _data._metrics[1].apparentEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_APPARENT_ENERGY) * 10;
1065 _data._metrics[1].activeEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_ACTIVE_ENERGY_IMPORTED) * 10;
1066 _data._metrics[1].activeEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_ACTIVE_ENERGY_RETURNED) * 10;
1067 _data._metrics[1].reactiveEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_REACTIVE_ENERGY_IMPORTED) * 10;
1068 _data._metrics[1].reactiveEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_REACTIVE_ENERGY_RETURNED) * 10;
1069 _data._metrics[1].phaseAngleU = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_PHASE_ANGLE_U) * 0.01f;
1070 _data._metrics[1].phaseAngleI = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_PHASE_ANGLE_I) * 0.01f;
1071 _data._metrics[1].phaseAngleUI = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_PHASE_ANGLE_UI) * 0.01f;
1072 _data._metrics[1].thdU = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_THD_U) * 0.01f;
1073 _data._metrics[1].thdI = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_B_THD_I) * 0.01f;
1076 _data._metrics[2].frequency = frequency;
1077 _data._metrics[2].voltage = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_VOLTAGE) * 0.01f;
1078 _data._metrics[2].current = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_CURRENT) * 0.01f;
1079 _data._metrics[2].activePower = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_ACTIVE_POWER) * (sign2 ? -1.0f : 1.0f);
1080 _data._metrics[2].reactivePower = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_REACTIVE_POWER) * (sign6 ? -1.0f : 1.0f);
1081 _data._metrics[2].apparentPower = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_APPARENT_POWER);
1082 _data._metrics[2].powerFactor = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_POWER_FACTOR) * 0.001f;
1083 _data._metrics[2].activeEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_ACTIVE_ENERGY) * 10;
1084 _data._metrics[2].reactiveEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_REACTIVE_ENERGY) * 10;
1085 _data._metrics[2].apparentEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_APPARENT_ENERGY) * 10;
1086 _data._metrics[2].activeEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_ACTIVE_ENERGY_IMPORTED) * 10;
1087 _data._metrics[2].activeEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_ACTIVE_ENERGY_RETURNED) * 10;
1088 _data._metrics[2].reactiveEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_REACTIVE_ENERGY_IMPORTED) * 10;
1089 _data._metrics[2].reactiveEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_REACTIVE_ENERGY_RETURNED) * 10;
1090 _data._metrics[2].phaseAngleU = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_PHASE_ANGLE_U) * 0.01f;
1091 _data._metrics[2].phaseAngleI = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_PHASE_ANGLE_I) * 0.01f;
1092 _data._metrics[2].phaseAngleUI = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_PHASE_ANGLE_UI) * 0.01f;
1093 _data._metrics[2].thdU = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_THD_U) * 0.01f;
1094 _data._metrics[2].thdI = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_PHASE_C_THD_I) * 0.01f;
1097 _data.aggregate.frequency = frequency;
1098 _data.aggregate.activePower = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_ACTIVE_POWER) * (sign3 ? -1.0f : 1.0f);
1099 _data.aggregate.reactivePower = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_REACTIVE_POWER) * (sign7 ? -1.0f : 1.0f);
1100 _data.aggregate.apparentPower = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_APPARENT_POWER);
1101 _data.aggregate.powerFactor = _register16(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_POWER_FACTOR) * 0.001f;
1102 _data.aggregate.activeEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_ACTIVE_ENERGY) * 10;
1103 _data.aggregate.reactiveEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_REACTIVE_ENERGY) * 10;
1104 _data.aggregate.apparentEnergy = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_APPARENT_ENERGY) * 10;
1105 _data.aggregate.activeEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_ACTIVE_ENERGY_IMPORTED) * 10;
1106 _data.aggregate.activeEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_ACTIVE_ENERGY_RETURNED) * 10;
1107 _data.aggregate.reactiveEnergyImported = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_REACTIVE_ENERGY_IMPORTED) * 10;
1108 _data.aggregate.reactiveEnergyReturned = _register32(_buffer, registerStart, registerSize, JSY_333_REGISTER_TOTAL_REACTIVE_ENERGY_RETURNED) * 10;
1109 _data.aggregate.current = _data._metrics[0].current + _data._metrics[1].current + _data._metrics[2].current;
1110 _data.aggregate.voltage = _data.aggregate.current == 0 ? NAN : _data.aggregate.apparentPower / _data.aggregate.current;
1122 _callback(EventType::EVT_READ, _data);
1134 return MYCILA_JSY_MK_UNKNOWN;
1136 LOGD(TAG,
"readModel(0x%02X)", address);
1138 std::lock_guard<std::mutex> lock(_mutex);
1140#ifdef MYCILA_JSY_DEBUG
1141 Serial.printf(
"[JSY] readModel(0x%02X)\n", address);
1144 memcpy(_buffer, JSY_REQUEST_READ_MODEL, JSY_REQUEST_READ_MODEL_LEN);
1145 _send(address, JSY_REQUEST_READ_MODEL_LEN);
1146 ReadResult result = _timedRead(address, JSY_RESPONSE_SIZE_READ_MODEL, _baudRate);
1148 if (result != ReadResult::READ_SUCCESS) {
1149 return MYCILA_JSY_MK_UNKNOWN;
1152 return (_buffer[JSY_RESPONSE_DATA] << 8) + _buffer[JSY_RESPONSE_DATA + 1];
1159Mycila::JSY::Mode Mycila::JSY::_readMode(
const uint8_t address,
const uint16_t model) {
1161 return Mode::UNKNOWN;
1164 case MYCILA_JSY_MK_163:
1165 case MYCILA_JSY_MK_193:
1166 case MYCILA_JSY_MK_194:
1167 case MYCILA_JSY_MK_333:
1169 case MYCILA_JSY_MK_227:
1170 case MYCILA_JSY_MK_229:
1172 case MYCILA_JSY_MK_1031:
1175 return Mode::UNKNOWN;
1178 LOGD(TAG,
"readMode(0x%02X)", address);
1180 std::lock_guard<std::mutex> lock(_mutex);
1182#ifdef MYCILA_JSY_DEBUG
1183 Serial.printf(
"[JSY] readMode(0x%02X)\n", address);
1186 memcpy(_buffer, JSY_REQUEST_READ_MODE, JSY_REQUEST_READ_MODE_LEN);
1187 _send(address, JSY_REQUEST_READ_MODE_LEN);
1188 ReadResult result = _timedRead(address, JSY_RESPONSE_SIZE_READ_MODE, _baudRate);
1190 if (result != ReadResult::READ_SUCCESS) {
1191 return Mode::UNKNOWN;
1194 switch (_buffer[JSY_RESPONSE_DATA]) {
1200 return Mode::UNKNOWN;
1204bool Mycila::JSY::_setMode(
const uint8_t address,
const uint16_t model,
const Mode mode) {
1208 if (mode == Mode::UNKNOWN)
1212 case MYCILA_JSY_MK_163:
1213 case MYCILA_JSY_MK_193:
1214 case MYCILA_JSY_MK_194:
1215 case MYCILA_JSY_MK_333:
1216 return mode == Mode::AC;
1217 case MYCILA_JSY_MK_227:
1218 case MYCILA_JSY_MK_229:
1219 return mode == Mode::DC;
1220 case MYCILA_JSY_MK_1031:
1226 LOGD(TAG,
"setMode(0x%02X) mode=%s", address, mode == Mode::AC ?
"AC" :
"DC");
1228 std::lock_guard<std::mutex> lock(_mutex);
1230#ifdef MYCILA_JSY_DEBUG
1231 Serial.printf(
"[JSY] setMode(0x%02X, %s)\n", address, mode == Mode::AC ?
"AC" :
"DC");
1234 memcpy(_buffer, JSY_REQUEST_SWITCH_MODE, JSY_REQUEST_SWITCH_MODE_LEN);
1236 _buffer[JSY_REQUEST_SET_MODE] = mode == Mode::AC ? JSY_MODE_AC : JSY_MODE_DC;
1238 _send(address, JSY_REQUEST_SWITCH_MODE_LEN);
1239 ReadResult result = _timedRead(address, JSY_RESPONSE_SIZE_SWITCH_MODE, _baudRate);
1241 return result == ReadResult::READ_SUCCESS;
1252 LOGD(TAG,
"resetEnergy(0x%02X)", address);
1254 std::lock_guard<std::mutex> lock(_mutex);
1256#ifdef MYCILA_JSY_DEBUG
1257 Serial.printf(
"[JSY] resetEnergy(0x%02X)\n", address);
1260 memcpy(_buffer, JSY_REQUEST_RESET_ENERGY, JSY_REQUEST_RESET_ENERGY_LEN);
1261 _send(address, JSY_REQUEST_RESET_ENERGY_LEN);
1262 ReadResult result = _timedRead(address, JSY_RESPONSE_SIZE_RESET_ENERGY, _baudRate);
1264 return result == ReadResult::READ_SUCCESS;
1271Mycila::JSY::BaudRate Mycila::JSY::getMinAvailableBaudRate()
const {
1273 return BaudRate::UNKNOWN;
1274 return getMinAvailableBaudRate(_model);
1277Mycila::JSY::BaudRate Mycila::JSY::getMinAvailableBaudRate(uint16_t model) {
1279 case MYCILA_JSY_MK_163:
1280 case MYCILA_JSY_MK_193:
1281 case MYCILA_JSY_MK_194:
1282 case MYCILA_JSY_MK_227:
1283 case MYCILA_JSY_MK_229:
1284 return BaudRate::BAUD_1200;
1285 return BaudRate::BAUD_1200;
1286 case MYCILA_JSY_MK_1031:
1287 case MYCILA_JSY_MK_333:
1288 return BaudRate::BAUD_4800;
1290 return BaudRate::UNKNOWN;
1296 return BaudRate::UNKNOWN;
1302 case MYCILA_JSY_MK_163:
1303 case MYCILA_JSY_MK_227:
1304 case MYCILA_JSY_MK_229:
1305 return BaudRate::BAUD_9600;
1306 case MYCILA_JSY_MK_1031:
1307 case MYCILA_JSY_MK_333:
1308 return BaudRate::BAUD_19200;
1309 case MYCILA_JSY_MK_193:
1310 case MYCILA_JSY_MK_194:
1311 return BaudRate::BAUD_38400;
1313 return BaudRate::UNKNOWN;
1324 return getMinAvailableBaudRate(model) <= baudRate && baudRate <= getMaxAvailableBaudRate(model);
1328 return _set(address, address ? address : (_lastAddress ? _lastAddress : MYCILA_JSY_ADDRESS_DEFAULT), baudRate);
1332 return _set(address, newAddress, _baudRate);
1335bool Mycila::JSY::_set(
const uint8_t address,
const uint8_t newAddress,
const BaudRate newBaudRate) {
1339 if (newBaudRate == BaudRate::UNKNOWN)
1342 if (newAddress == MYCILA_JSY_ADDRESS_UNKNOWN)
1345 LOGD(TAG,
"set(0x%02X) address=0x%02X, bauds=%" PRIu32, address, newAddress, newBaudRate);
1347 std::lock_guard<std::mutex> lock(_mutex);
1349#ifdef MYCILA_JSY_DEBUG
1350 Serial.printf(
"[JSY] _set(0x%02X)\n", address);
1353 memcpy(_buffer, JSY_REQUEST_SET_COM, JSY_REQUEST_SET_COM_LEN);
1356 _buffer[JSY_REQUEST_SET_ADDRESS] = newAddress;
1359 switch (newBaudRate) {
1360 case BaudRate::BAUD_1200:
1361 _buffer[JSY_REQUEST_SET_BAUDS] = 0x03;
1363 case BaudRate::BAUD_2400:
1364 _buffer[JSY_REQUEST_SET_BAUDS] = 0x04;
1366 case BaudRate::BAUD_4800:
1367 _buffer[JSY_REQUEST_SET_BAUDS] = 0x05;
1369 case BaudRate::BAUD_9600:
1370 _buffer[JSY_REQUEST_SET_BAUDS] = 0x06;
1372 case BaudRate::BAUD_19200:
1373 _buffer[JSY_REQUEST_SET_BAUDS] = 0x07;
1375 case BaudRate::BAUD_38400:
1376 _buffer[JSY_REQUEST_SET_BAUDS] = 0x08;
1383 _send(address, JSY_REQUEST_SET_COM_LEN);
1384 ReadResult result = _timedRead(address, JSY_RESPONSE_SIZE_SET_COM, _baudRate);
1387 if (result != ReadResult::READ_SUCCESS && result != ReadResult::READ_ERROR_ADDRESS) {
1392 if (result == ReadResult::READ_ERROR_ADDRESS && _lastAddress != newAddress) {
1396 _openSerial(newBaudRate);
1398 bool success =
false;
1399 for (
int i = 0; i < MYCILA_JSY_RETRY_COUNT; i++) {
1400 if (_canRead(address, newBaudRate)) {
1408 _baudRate = newBaudRate;
1411 if (_destinationAddress != MYCILA_JSY_ADDRESS_BROADCAST && _destinationAddress == address) {
1412 _destinationAddress = newAddress;
1416 LOGE(TAG,
"Unable to read JSY @ 0x%02X at speed: %" PRIu32, address, newBaudRate);
1417 if (_baudRate != BaudRate::UNKNOWN) {
1418 _openSerial(_baudRate);
1429#ifdef MYCILA_JSON_SUPPORT
1430void Mycila::JSY::toJson(
const JsonObject& root)
const {
1431 root[
"enabled"] = _enabled;
1432 root[
"time"] = _time;
1433 root[
"speed"] = _baudRate;
1442bool Mycila::JSY::_canRead(
const uint8_t address, BaudRate baudRate) {
1443#ifdef MYCILA_JSY_DEBUG
1444 Serial.printf(
"[JSY] _canRead(0x%02X)\n", address);
1446 memcpy(_buffer, JSY_REQUEST_READ_MODEL, JSY_REQUEST_READ_MODEL_LEN);
1447 _send(address, JSY_REQUEST_READ_MODEL_LEN);
1448 return _timedRead(address, JSY_RESPONSE_SIZE_READ_MODEL, baudRate) == ReadResult::READ_SUCCESS;
1451Mycila::JSY::ReadResult Mycila::JSY::_timedRead(
const uint8_t expectedAddress,
const size_t expectedLen,
const BaudRate baudRate) {
1453 while (count < expectedLen) {
1454 size_t read = _serial->readBytes(_buffer + count, expectedLen - count);
1462#ifdef MYCILA_JSY_DEBUG
1463 Serial.printf(
"[JSY] timedRead(0x%02X) %d < ", expectedAddress, count);
1464 for (
size_t i = 0; i < count; i++) {
1465 Serial.printf(
"0x%02X ", _buffer[i]);
1474 LOGD(TAG,
"timedRead(0x%02X) timeout", expectedAddress);
1475 return ReadResult::READ_TIMEOUT;
1479 if (count != expectedLen) {
1480 LOGD(TAG,
"timedRead(0x%02X) error: len %d != %d", expectedAddress, count, expectedLen);
1481 return ReadResult::READ_ERROR_COUNT;
1485 uint16_t crc = _crc16(_buffer, expectedLen - 2);
1486 if (_buffer[expectedLen - 2] != LOBYTE(crc) || _buffer[expectedLen - 1] != HIBYTE(crc)) {
1487 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));
1488 return ReadResult::READ_ERROR_CRC;
1491 _lastAddress = _buffer[JSY_RESPONSE_ADDRESS];
1494 if (expectedAddress != MYCILA_JSY_ADDRESS_BROADCAST && expectedAddress != _lastAddress) {
1495 LOGD(TAG,
"timedRead(0x%02X) error: wrong device address 0x%02X", expectedAddress, _lastAddress);
1496 return ReadResult::READ_ERROR_ADDRESS;
1499 return ReadResult::READ_SUCCESS;
1502void Mycila::JSY::_send(
const uint8_t address,
const size_t len) {
1504 _buffer[JSY_REQUEST_ADDRESS] = address;
1507 uint16_t crc = _crc16(_buffer, len - 2);
1508 _buffer[len - 2] = LOBYTE(crc);
1509 _buffer[len - 1] = HIBYTE(crc);
1511#ifdef MYCILA_JSY_DEBUG
1512 Serial.printf(
"[JSY] send(0x%02X) %d > ", address, len);
1513 for (
size_t i = 0; i < len; i++) {
1514 Serial.printf(
"0x%02X ", _buffer[i]);
1519 _serial->flush(
false);
1520 _serial->write(_buffer, len);
1523size_t Mycila::JSY::_drop() {
1525 if (_serial->available()) {
1526#ifdef MYCILA_JSY_DEBUG
1527 Serial.printf(
"[JSY] drop < ");
1529 while (_serial->available()) {
1530#ifdef MYCILA_JSY_DEBUG
1531 Serial.printf(
"0x%02X ", _serial->read());
1537#ifdef MYCILA_JSY_DEBUG
1544void Mycila::JSY::_openSerial(BaudRate baudRate) {
1545 LOGD(TAG,
"openSerial(%" PRIu32
")", baudRate);
1546 _serial->begin(baudRate, SERIAL_8N1, _pinRX, _pinTX);
1547 _serial->setTimeout(MYCILA_JSY_READ_TIMEOUT_MS);
1550 while (!_serial->availableForWrite())
1553 _serial->flush(
false);
1556Mycila::JSY::BaudRate Mycila::JSY::_detectBauds(
const uint8_t address) {
1557 for (
int i = 0; i < AUTO_DETECT_BAUD_RATES_COUNT * 2; i++) {
1558 BaudRate baudRate = AUTO_DETECT_BAUD_RATES[i % AUTO_DETECT_BAUD_RATES_COUNT];
1559 LOGD(TAG,
"find(0x%02X) %" PRIu32
" bauds", address, baudRate);
1560 _openSerial(baudRate);
1561 for (
int j = 0; j < MYCILA_JSY_RETRY_COUNT; j++) {
1562 if (_canRead(address, baudRate)) {
1567 return BaudRate::UNKNOWN;
1576inline uint16_t Mycila::JSY::_crc16(
const uint8_t* data,
size_t len) {
1577 uint16_t crc = 0xFFFF;
1579 uint8_t temp = *(data++) ^ LOBYTE(crc);
1580 crc = (crc >> 8) ^ pgm_read_word_near(CRCTable + temp);
1585uint8_t Mycila::JSY::_register8(
const uint8_t* buffer,
const uint16_t registerStart,
const uint16_t registerSize,
const uint16_t registerAddress, uint8_t index) {
1586 return buffer[JSY_RESPONSE_DATA + (registerAddress - registerStart) * registerSize + index];
1589uint16_t Mycila::JSY::_register16(
const uint8_t* buffer,
const uint16_t registerStart,
const uint16_t registerSize,
const uint16_t registerAddress) {
1590 const size_t start = JSY_RESPONSE_DATA + (registerAddress - registerStart) * registerSize;
1591 return (buffer[start] << 8) + buffer[start + 1];
1594uint32_t Mycila::JSY::_register32(
const uint8_t* buffer,
const uint16_t registerStart,
const uint16_t registerSize,
const uint16_t registerAddress) {
1595 const size_t start = JSY_RESPONSE_DATA + (registerAddress - registerStart) * registerSize;
1596 return (buffer[start] << 24) +
1597 (buffer[start + 1] << 16) +
1598 (buffer[start + 2] << 8) +
1599 (buffer[start + 3]);
1602const char* Mycila::JSY::getModelName(uint16_t model) {
1604 case MYCILA_JSY_MK_1031:
1605 return MYCILA_JSY_MK_1031_NAME;
1606 case MYCILA_JSY_MK_163:
1607 return MYCILA_JSY_MK_163_NAME;
1608 case MYCILA_JSY_MK_193:
1609 return MYCILA_JSY_MK_193_NAME;
1610 case MYCILA_JSY_MK_194:
1611 return MYCILA_JSY_MK_194_NAME;
1612 case MYCILA_JSY_MK_227:
1613 return MYCILA_JSY_MK_227_NAME;
1614 case MYCILA_JSY_MK_229:
1615 return MYCILA_JSY_MK_229_NAME;
1616 case MYCILA_JSY_MK_333:
1617 return MYCILA_JSY_MK_333_NAME;
1619 return emptyString.c_str();
1623void Mycila::JSY::_jsyTask(
void* params) {
1624 JSY* jsy =
reinterpret_cast<JSY*
>(params);
1625 while (jsy->_enabled) {
1627 if (jsy->_pause > 0) {
1632 }
else if (jsy->_pause > 0) {
1638 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.