Instrument Neutral Distributed Interface INDI 2.2.5
wandererbox_plus_v3.cpp
Go to the documentation of this file.
1/*******************************************************************************
2 Copyright(c) 2024 Frank Wang. All rights reserved.
3
4 WandererBox Plus V3
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2 of the License, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20
21 The full GNU General Public License is included in this distribution in the
22 file called LICENSE.
23*******************************************************************************/
24
25#include "wandererbox_plus_v3.h"
26#include "indicom.h"
28#include <cerrno>
29#include <cstring>
30#include <string>
31#include <memory>
32#include <termios.h>
33#include <unistd.h>
34#include <inttypes.h>
35#include <sys/ioctl.h>
36#include <cmath>
37
38// We declare an auto pointer to WandererBoxPlusV3.
39static std::unique_ptr<WandererBoxPlusV3> WandererBoxplusv3(new WandererBoxPlusV3());
40
41
42
43WandererBoxPlusV3::WandererBoxPlusV3() : INDI::DefaultDevice(), INDI::WeatherInterface(this)
44{
45 setVersion(1, 0);
46}
47
49{
50
53
54 WI::initProperties(ENVIRONMENT_TAB, ENVIRONMENT_TAB);
55
57
58
59 // Calibrate
60 CalibrateSP[0].fill("Calibrate", "Calibrate Current", ISS_OFF);
61 CalibrateSP.fill(getDeviceName(), "Calibrate_DEVICE", "Calibrate Current", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1,60, IPS_IDLE);
62
63 // Power Monitor
64 PowerMonitorNP[VOLTAGE].fill("VOLTAGE", "Voltage (V)", "%4.2f", 0, 999, 100, 0);
65 PowerMonitorNP[TOTAL_CURRENT].fill("TOTAL_CURRENT", "Total Current (A)", "%4.2f", 0, 999, 100, 0);
66 PowerMonitorNP.fill(getDeviceName(), "POWER_Monitor", "Power Monitor", MAIN_CONTROL_TAB, IP_RO,60, IPS_IDLE);
67
68
69 // USB Control
70 USBControlSP[INDI_ENABLED].fill("INDI_ENABLED", "On", ISS_OFF);
71 USBControlSP[INDI_DISABLED].fill("INDI_DISABLED", "Off", ISS_OFF);
72 USBControlSP.fill(getDeviceName(), "USB", "USB", MAIN_CONTROL_TAB, IP_RW,ISR_1OFMANY, 60, IPS_IDLE);
73
74
75 // DC3
76 DC3ControlNP[DC3].fill( "DC3", "Dew Heater (PWM)", "%.2f", 0, 255, 5, 0);
77 DC3ControlNP.fill(getDeviceName(), "PWM", "DC3", DC3_TAB, IP_RW, 60, IPS_IDLE);
78
79 // DC2SET
80 setDC2voltageNP[setDC2voltage].fill( "DC2SET", "Adjustable Voltage", "%.2f", 5, 13.2, 0.1, 0);
81 setDC2voltageNP.fill(getDeviceName(), "DC2voltageSET", "Set DC2", MAIN_CONTROL_TAB, IP_RW, 60, IPS_IDLE);
82 // DC2 Control
83 dc2ControlSP[INDI_ENABLED].fill( "INDI_ENABLED", "On", ISS_OFF);
84 dc2ControlSP[INDI_DISABLED].fill( "INDI_DISABLED", "Off", ISS_ON);
85 dc2ControlSP.fill(getDeviceName(), "DC2", "DC2", MAIN_CONTROL_TAB, IP_RW,ISR_1OFMANY, 60, IPS_IDLE);
86
87 // DC4-6 Control
88 DC4_6ControlSP[INDI_ENABLED].fill( "INDI_ENABLED", "On", ISS_OFF);
89 DC4_6ControlSP[INDI_DISABLED].fill( "INDI_DISABLED", "Off", ISS_ON);
90 DC4_6ControlSP.fill(getDeviceName(), "DC4-6", "DC4-6", MAIN_CONTROL_TAB, IP_RW,ISR_1OFMANY, 60, IPS_IDLE);
91
92 // DC3 TEMP Difference Control
93 DC3diffSP[DC3_Manual].fill( "Manual", "Manual", ISS_ON);
94 DC3diffSP[DC3_DPD_Mode].fill( "DPD_Mode", "DPD Mode", ISS_OFF);
95 DC3diffSP[DC3_CT_Mode].fill( "CT_Mode", "CT Mode", ISS_OFF);
96 DC3diffSP.fill(getDeviceName(), "DC3_DIFF", "DC3 Dew Mode", DC3_TAB, IP_RW,ISR_1OFMANY, 60, IPS_IDLE);
97
98 DC3diffSETNP[DC3DIFFSET].fill( "DC3 Auto Control", "Dew Point Difference(C)", "%.2f", 10, 30, 1, 0);
99 DC3diffSETNP.fill(getDeviceName(), "DC3_DIFF_SET", "DPD Mode", DC3_TAB, IP_RW, 60, IPS_IDLE);
100
101 DC3constSETNP[DC3CONSTSET].fill( "DC3 Auto Control", "Temperature(C)", "%.2f", 0, 40, 1, 0);
102 DC3constSETNP.fill(getDeviceName(), "DC3_CONST_SET", "CT Mode", DC3_TAB, IP_RW, 60, IPS_IDLE);
103
104 //ENV
105 ENVMonitorNP[Probe1_Temp].fill( "Probe1_Temp", "Probe1 Temperature (C)", "%4.2f", 0, 999, 100, 0);
106 ENVMonitorNP[ENV_Humidity].fill( "ENV_Humidity", "Ambient Humidity %", "%4.2f", 0, 999, 100, 0);
107 ENVMonitorNP[ENV_Temp].fill( "ENV_Temp", "Ambient Temperature (C)", "%4.2f", 0, 999, 100, 0);
108 ENVMonitorNP[DEW_Point].fill( "DEW_Point", "Dew Point (C)", "%4.2f", 0, 999, 100, 0);
109 ENVMonitorNP.fill(getDeviceName(), "ENV_Monitor", "Environment", SENSORS_TAB, IP_RO,60, IPS_IDLE);
110
111 // Weather Interface Parameters
112 addParameter("WEATHER_TEMPERATURE", "Temperature (C)", -15, 35, 15);
113 addParameter("WEATHER_HUMIDITY", "Humidity %", 0, 100, 15);
114 addParameter("WEATHER_DEWPOINT", "Dew Point (C)", 0, 100, 15);
115 setCriticalParameter("WEATHER_TEMPERATURE");
116 serialConnection = new Connection::Serial(this);
118 serialConnection->registerHandshake([&]()
119 {
120 return getData();
121 });
122 registerConnection(serialConnection);
123
124 return true;
125}
126
127bool WandererBoxPlusV3::getData()
128{
129 try
130 {
131 PortFD = serialConnection->getPortFD();
132 tcflush(PortFD, TCIOFLUSH);
133 int nbytes_read_name = 0,rc=-1;
134 char name[64] = {0};
135
136 //Device Model//////////////////////////////////////////////////////////////////////////////////////////////////////
137 if ((rc = tty_read_section(PortFD, name, 'A', 3, &nbytes_read_name)) != TTY_OK)
138 {
139 char errorMessage[MAXRBUF];
140 tty_error_msg(rc, errorMessage, MAXRBUF);
141 LOGF_INFO("No data received, the device may not be WandererBox Plus V3, please check the serial port!","Updated");
142 LOGF_ERROR("Device read error: %s", errorMessage);
143 return false;
144 }
145 name[nbytes_read_name - 1] = '\0';
146 if(strcmp(name, "ZXWBProV3")==0||strcmp(name, "WandererCoverV4")==0||strcmp(name, "UltimateV2")==0||strcmp(name, "PlusV2")==0)
147 {
148 LOGF_INFO("The device is not WandererBox Plus V3!","Updated");
149 return false;
150 }
151 if(strcmp(name, "ZXWBPlusV3")!=0)
152 {
153 LOGF_ERROR("Device is not WandererBox Plus V3 (got '%s'). Wrong port or device.", name);
154 return false;
155 }
156 // Frimware version/////////////////////////////////////////////////////////////////////////////////////////////
157 int nbytes_read_version = 0;
158 char version[64] = {0};
159 tty_read_section(PortFD, version, 'A', 5, &nbytes_read_version);
160
161 version[nbytes_read_version - 1] = '\0';
162 firmware=std::atoi(version);
163
164
165 // Temp probe 1//////////////////////////////////////////////////////////////////////////////////////////
166 char temp1[64] = {0};
167 int nbytes_read_temp1= 0;
168 tty_read_section(PortFD, temp1, 'A', 5, &nbytes_read_temp1);
169 temp1[nbytes_read_temp1 - 1] = '\0';
170 temp1read = std::strtod(temp1,NULL);
171
172 // DHTH//////////////////////////////////////////////////////////////////////////////////////////
173 char DHTH[64] = {0};
174 int nbytes_read_DHTH= 0;
175 tty_read_section(PortFD, DHTH, 'A', 5, &nbytes_read_DHTH);
176 DHTH[nbytes_read_DHTH - 1] = '\0';
177 DHTHread = std::strtod(DHTH,NULL);
178
179 // DHTT//////////////////////////////////////////////////////////////////////////////////////////
180 char DHTT[64] = {0};
181 int nbytes_read_DHTT= 0;
182 tty_read_section(PortFD, DHTT, 'A', 5, &nbytes_read_DHTT);
183 DHTT[nbytes_read_DHTT - 1] = '\0';
184 DHTTread = std::strtod(DHTT,NULL);
185 updateENV(temp1read,DHTHread,DHTTread);
186
187 // Total current//////////////////////////////////////////////////////////////////////////////////////////
188 char Tcurrent[64] = {0};
189 int nbytes_read_Tcurrent= 0;
190 tty_read_section(PortFD, Tcurrent, 'A', 5, &nbytes_read_Tcurrent);
191 Tcurrent[nbytes_read_Tcurrent - 1] = '\0';
192 Tcurrentread = std::strtod(Tcurrent,NULL);
193
194 // Voltage//////////////////////////////////////////////////////////////////////////////////////////
195 char voltage[64] = {0};
196 int nbytes_read_voltage= 0;
197 tty_read_section(PortFD, voltage, 'A', 5, &nbytes_read_voltage);
198 voltage[nbytes_read_voltage - 1] = '\0';
199 voltageread = std::strtod(voltage,NULL);
200 updatePower(Tcurrentread,voltageread);
201
202 // USB//////////////////////////////////////////////////////////////////////////////////////////
203 char USB[64] = {0};
204 int nbytes_read_USB= 0;
205 tty_read_section(PortFD, USB, 'A', 5, &nbytes_read_USB);
206 USB[nbytes_read_USB - 1] = '\0';
207 USBread = std::stoi(USB);
208 updateUSB(USBread);
209
210
211 // DC2//////////////////////////////////////////////////////////////////////////////////////////
212 char DC2[64] = {0};
213 int nbytes_read_DC2= 0;
214 tty_read_section(PortFD, DC2, 'A', 5, &nbytes_read_DC2);
215 DC2[nbytes_read_DC2 - 1] = '\0';
216 DC2read = std::stoi(DC2);
217 updateDC2(DC2read);
218
219 // DC3//////////////////////////////////////////////////////////////////////////////////////////
220 char DC3[64] = {0};
221 int nbytes_read_DC3= 0;
222 tty_read_section(PortFD, DC3, 'A', 5, &nbytes_read_DC3);
223 DC3[nbytes_read_DC3 - 1] = '\0';
224 DC3read = std::stoi(DC3);
225 updateDC3(DC3read);
226
227
228 // DC4_6//////////////////////////////////////////////////////////////////////////////////////////
229 char DC4_6[64] = {0};
230 int nbytes_read_DC4_6= 0;
231 tty_read_section(PortFD, DC4_6, 'A', 5, &nbytes_read_DC4_6);
232 DC4_6[nbytes_read_DC4_6 - 1] = '\0';
233 DC4_6read =std::stoi(DC4_6);
234 updateDC4_6(DC4_6read);
235
236
237 // DC2SET//////////////////////////////////////////////////////////////////////////////////////////
238 char DC2SET[64] = {0};
239 int nbytes_read_DC2SET= 0;
240 tty_read_section(PortFD, DC2SET, 'A', 5, &nbytes_read_DC2SET);
241 DC2SET[nbytes_read_DC2SET - 1] = '\0';
242 //LOGF_INFO("All Data Updated","Updated");
243 DC2SETread = std::stoi(DC2SET);
244 updateDC2SET(DC2SETread);
245
246
247 //DC3 DEW CONTROL
248 if(DC3diffSP[DC3_DPD_Mode].getState() == ISS_ON)
249 {
250 if(temp1read<ENVMonitorNP[DEW_Point].value+DC3diffSETNP[DC3DIFFSET].value)
251 sendCommand("3255");
252 else
253 sendCommand("3000");
254 }
255
256 if(DC3CONSTMODE==true )
257 {
258 if(temp1read<DC3constSETNP[DC3CONSTSET].value)
259 sendCommand("3255");
260 else
261 sendCommand("3000");
262 }
263 if (DC3diffSP[DC3_DPD_Mode].getState() == ISS_ON&&ENVMonitorNP[Probe1_Temp].value==-127)
264 {
265 DC3DIFFMODE=false;
266 DC3CONSTMODE=false;
267 defineProperty(DC3ControlNP);
268 deleteProperty(DC3diffSETNP);
269 deleteProperty(DC3constSETNP);
270 LOGF_ERROR("Temp probe 1 not connected, Dew Point Difference Mode for DC3 has exited!","Updated");
271 LOGF_INFO("You need to insert the probe firmly to the end!","Updated");
272 DC3diffSP[DC3_Manual].setState( ISS_ON);
273 DC3diffSP[DC3_DPD_Mode].setState( ISS_OFF);
274 DC3diffSP[DC3_CT_Mode].setState( ISS_OFF);
275 DC3diffSP.setState(IPS_OK);
276 DC3diffSP.apply();
277 }
278 if (DC3diffSP[DC3_DPD_Mode].getState() == ISS_ON&&isnan(ENVMonitorNP[DEW_Point].value)==1)
279 {
280 DC3DIFFMODE=false;
281 DC3CONSTMODE=false;
282 defineProperty(DC3ControlNP);
283 deleteProperty(DC3diffSETNP);
284 deleteProperty(DC3constSETNP);
285 LOGF_ERROR("DHT22 Humidity&Temperature sensor not connected, Dew Point Difference Mode for DC3 has exited!","Updated");
286 DC3diffSP[DC3_Manual].setState( ISS_ON);
287 DC3diffSP[DC3_DPD_Mode].setState( ISS_OFF);
288 DC3diffSP[DC3_CT_Mode].setState( ISS_OFF);
289 DC3diffSP.setState(IPS_OK);
290 DC3diffSP.apply();
291 }
292 if (DC3diffSP[DC3_CT_Mode].getState() == ISS_ON&&ENVMonitorNP[Probe1_Temp].value==-127)
293 {
294 DC3DIFFMODE=false;
295 DC3CONSTMODE=false;
296 defineProperty(DC3ControlNP);
297 deleteProperty(DC3diffSETNP);
298 deleteProperty(DC3constSETNP);
299 LOGF_ERROR("Temp probe 1 not connected, Constant Temperature Mode for DC3 has exited!","Updated");
300 LOGF_INFO("You need to insert the probe firmly to the end!","Updated");
301 DC3diffSP[DC3_Manual].setState( ISS_ON);
302 DC3diffSP[DC3_DPD_Mode].setState( ISS_OFF);
303 DC3diffSP[DC3_CT_Mode].setState( ISS_OFF);
304 DC3diffSP.setState(IPS_OK);
305 DC3diffSP.apply();
306 }
307
308 }
309 catch(std::exception& e)
310 {
311 //LOGF_INFO("Data read failed","failed");
312 }
313 return true;
314}
315
316
317
318void WandererBoxPlusV3::updateENV(double temp1,double DHTH,double DHTT)
319{
320 ENVMonitorNP[Probe1_Temp].setValue(temp1);
321 ENVMonitorNP[ENV_Humidity].setValue(DHTH);
322 ENVMonitorNP[ENV_Temp].setValue(DHTT);
323 double dewPoint = (237.7 * ((17.27 * DHTT) / (237.7 + DHTT) + std::log((DHTH / 100)))) / (17.27 - ((17.27 * DHTT) / (237.7 + DHTT) + std::log((DHTH / 100))));
324 ENVMonitorNP[DEW_Point].setValue(dewPoint);
325 ENVMonitorNP.setState(IPS_OK);
326 ENVMonitorNP.apply();
327
328 // Update Weather Interface parameters
329 setParameterValue("WEATHER_TEMPERATURE", DHTT);
330 setParameterValue("WEATHER_HUMIDITY", DHTH);
331 setParameterValue("WEATHER_DEWPOINT", dewPoint);
336}
337
338
339void WandererBoxPlusV3::updatePower(double Tcurrent,double voltage)
340{
341 // Power Monitor
342 PowerMonitorNP[VOLTAGE].setValue(voltage);
343 PowerMonitorNP[TOTAL_CURRENT].setValue(Tcurrent);
344
345 PowerMonitorNP.setState(IPS_OK);
346 PowerMonitorNP.apply();
347}
348
349void WandererBoxPlusV3::updateUSB(int res)
350{
351 USBControlSP[INDI_ENABLED].setState( (res== 1) ? ISS_ON : ISS_OFF);
352 USBControlSP[INDI_DISABLED].setState( (res== 0) ? ISS_ON : ISS_OFF);
353 USBControlSP.setState((res== 1) ? IPS_OK : IPS_IDLE);
354 USBControlSP.apply();
355}
356
357void WandererBoxPlusV3::updateDC2(int res)
358{
359 dc2ControlSP[INDI_ENABLED].setState( (res== 1) ? ISS_ON : ISS_OFF);
360 dc2ControlSP[INDI_DISABLED].setState( (res== 0) ? ISS_ON : ISS_OFF);
361 dc2ControlSP.setState((res== 1) ? IPS_OK : IPS_IDLE);
362 dc2ControlSP.apply();
363}
364
365void WandererBoxPlusV3::updateDC3(int res)
366{
367 DC3ControlNP[0].setValue(res);
368 DC3ControlNP.setState(IPS_OK);
369 DC3ControlNP.apply();
370}
371
372
373void WandererBoxPlusV3::updateDC4_6(int res)
374{
375 DC4_6ControlSP[INDI_ENABLED].setState( (res== 1) ? ISS_ON : ISS_OFF);
376 DC4_6ControlSP[INDI_DISABLED].setState( (res== 0) ? ISS_ON : ISS_OFF);
377 DC4_6ControlSP.setState((res== 1) ? IPS_OK : IPS_IDLE);
378 DC4_6ControlSP.apply();
379}
380
381
382void WandererBoxPlusV3::updateDC2SET(double res)
383{
384 setDC2voltageNP[setDC2voltage].setValue(res/10);
385 setDC2voltageNP.setState(IPS_OK);
386 setDC2voltageNP.apply();
387}
388
389
390
392{
394
395 if (isConnected())
396 {
397
398 if(firmware>=20240216)
399 {
400 defineProperty(CalibrateSP);
401 LOGF_INFO("Firmware version: %d", firmware);
402 }
403 else
404 {
405 LOGF_INFO("The firmware is outdated, please upgrade to the latest firmware, or power reading calibration will be unavailable.","failed");
406 }
407 defineProperty(PowerMonitorNP);
408
409
410 defineProperty(USBControlSP);
411
412 defineProperty(setDC2voltageNP);
413 defineProperty(dc2ControlSP);
414
415 defineProperty(DC4_6ControlSP);
416
417
418 defineProperty(DC3diffSP);
419
420
421
422 //DC3////////////////////
423 if(DC3diffSP[DC3_DPD_Mode].getState() == ISS_ON)
424 {
425 deleteProperty(DC3constSETNP);
426 deleteProperty(DC3ControlNP);
427 defineProperty(DC3diffSETNP);
428 }
429 else if(DC3diffSP[DC3_CT_Mode].getState() == ISS_ON)
430 {
431 deleteProperty(DC3ControlNP);
432 deleteProperty(DC3diffSETNP);
433 defineProperty(DC3constSETNP);
434 }
435 else
436 {
437 defineProperty(DC3ControlNP);
438 deleteProperty(DC3diffSETNP);
439 deleteProperty(DC3constSETNP);
440 }
441 defineProperty(ENVMonitorNP);
442
443 // Weather
445
446 }
447 else
448 {
449
450 deleteProperty(CalibrateSP);
451 deleteProperty(PowerMonitorNP);
452 deleteProperty(ENVMonitorNP);
453
454 // Weather
456
457 deleteProperty(dc2ControlSP);
458 deleteProperty(setDC2voltageNP);
459 deleteProperty(DC4_6ControlSP);
460
461 deleteProperty(USBControlSP);
462
463
464 deleteProperty(DC3ControlNP);
465
466
467 deleteProperty(DC3diffSP);
468 deleteProperty(DC3diffSETNP);
469
470
471
472 }
473 return true;
474}
475
476bool WandererBoxPlusV3::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
477{
478 if (dev && !strcmp(dev, getDeviceName()))
479 {
480 if (strstr(name, "WEATHER_"))
481 return WI::processSwitch(dev, name, states, names, n);
482 }
483
484 // Calibrate
485 if (CalibrateSP.isNameMatch(name))
486 {
487 CalibrateSP.setState(sendCommand("66300744") ? IPS_OK : IPS_ALERT);
488 CalibrateSP.apply();
489 LOG_INFO("Calibrating Current Readings...");
490 return true;
491 }
492
493
494 // DC2 Control
495 if (dc2ControlSP.isNameMatch(name))
496 {
497 dc2ControlSP.update(states, names, n);
498 dc2ControlSP.setState(IPS_ALERT);
499 char cmd[128] = {0};
500 snprintf(cmd, 128, "12%d", (dc2ControlSP[INDI_ENABLED].getState() == ISS_ON) ? 1 : 0);
501 dc2ControlSP.setState( sendCommand(cmd) ? IPS_OK : IPS_ALERT);
502 dc2ControlSP.apply();
503
504 return true;
505 }
506 // DC4-6 Control
507 if (DC4_6ControlSP.isNameMatch(name))
508 {
509 DC4_6ControlSP.update(states, names, n);
510 DC4_6ControlSP.setState(IPS_ALERT);
511 char cmd[128] = {0};
512 snprintf(cmd, 128, "10%d", (DC4_6ControlSP[INDI_ENABLED].getState() == ISS_ON) ? 1 : 0);
513 DC4_6ControlSP.setState( sendCommand(cmd) ? IPS_OK : IPS_ALERT);
514 DC4_6ControlSP.apply();
515
516 return true;
517 }
518
519 // USB Control
520 if (USBControlSP.isNameMatch(name))
521 {
522 USBControlSP.update(states, names, n);
523 USBControlSP.setState(IPS_ALERT);
524 char cmd[128] = {0};
525 snprintf(cmd, 128, "11%d", (USBControlSP[INDI_ENABLED].getState() == ISS_ON) ? 1 : 0);
526 USBControlSP.setState( sendCommand(cmd) ? IPS_OK : IPS_ALERT);
527
528 return true;
529 }
530
531 // DC3 DEW
532 if (DC3diffSP.isNameMatch(name))
533 {
534 DC3diffSP.update(states, names, n);
535 DC3diffSP.setState(IPS_ALERT);
536 if(DC3diffSP[DC3_DPD_Mode].getState() == ISS_ON&&ENVMonitorNP[Probe1_Temp].value!=-127&&isnan(ENVMonitorNP[DEW_Point].value)==0)
537 {
538 DC3DIFFMODE=true;
539 DC3CONSTMODE=false;
540 deleteProperty(DC3ControlNP);
541 deleteProperty(DC3constSETNP);
542 defineProperty(DC3diffSETNP);
543
544 DC3diffSETNP.setState(IPS_OK);
545 DC3diffSETNP.apply();
546 DC3diffSP.setState(IPS_OK) ;
547 DC3diffSP.apply();
548 LOGF_INFO("Dew Point Difference Mode for DC3 activated! WandererBox will keep the dew heater at the temperature higher than the dew point by the set value.","Updated");
549 return true;
550 }
551 else if(DC3diffSP[DC3_DPD_Mode].getState() == ISS_ON&&(ENVMonitorNP[Probe1_Temp].value==-127||isnan(ENVMonitorNP[DEW_Point].value)==1))
552 {
553 DC3DIFFMODE=false;
554 DC3CONSTMODE=false;
555 DC3diffSP[DC3_Manual].setState( ISS_ON);
556 LOGF_INFO("Manual Mode for DC3 activated! Please adjust the duty cycle manually, you can also use DC3 as an ordinary switch.","Updated");
557 DC3diffSP.apply();
558 }
559 else if(DC3diffSP[DC3_CT_Mode].getState() == ISS_ON&&ENVMonitorNP[Probe1_Temp].value!=-127)
560 {
561 DC3CONSTMODE=true;
562 DC3DIFFMODE=false;
563 deleteProperty(DC3diffSETNP);
564 deleteProperty(DC3ControlNP);
565 defineProperty(DC3constSETNP);
566
567 DC3constSETNP.setState(IPS_OK);
568 DC3constSETNP.apply();
569 DC3diffSP.setState(IPS_OK) ;
570 DC3diffSP.apply();
571 LOGF_INFO("Constant Temperature Mode for DC3 activated! WandererBox will keep the dew heater at the set temperature.","Updated");
572 return true;
573 }
574 else if(DC3diffSP[DC3_CT_Mode].getState() == ISS_ON&&ENVMonitorNP[Probe1_Temp].value==-127)
575 {
576 DC3DIFFMODE=false;
577 DC3CONSTMODE=false;
578 DC3diffSP[DC3_Manual].setState( ISS_ON);
579 LOGF_INFO("Manual Mode for DC3 activated! Please adjust the duty cycle manually, you can also use DC3 as an ordinary switch.","Updated");
580 DC3diffSP.apply();
581 }
582 else
583 {
584 DC3DIFFMODE=false;
585 DC3CONSTMODE=false;
586 defineProperty(DC3ControlNP);
587 deleteProperty(DC3diffSETNP);
588 deleteProperty(DC3constSETNP);
589 DC3diffSP.setState(IPS_OK) ;
590 DC3diffSP.apply();
591 LOGF_INFO("Manual Mode for DC3 activated! Please adjust the duty cycle manually, you can also use DC3 as an ordinary switch.","Updated");
592 return true;
593 }
594
595 }
596
597
598 return DefaultDevice::ISNewSwitch(dev, name, states, names, n);
599}
600
601bool WandererBoxPlusV3::ISNewNumber(const char * dev, const char * name, double values[], char * names[], int n)
602{
603 if (dev && !strcmp(dev, getDeviceName()))
604 {
605 if (strstr(name, "WEATHER_"))
606 return WI::processNumber(dev, name, values, names, n);
607 // DC3
608 if (DC3ControlNP.isNameMatch(name))
609 {
610 bool rc1 = false;
611 for (int i = 0; i < n; i++)
612 {
613 rc1 = setDewPWM(3, static_cast<uint8_t>(values[i]));
614 }
615
616 DC3ControlNP.setState( (rc1) ? IPS_OK : IPS_ALERT);
617 if (DC3ControlNP.getState() == IPS_OK)
618 DC3ControlNP.update(values, names, n);
619 DC3ControlNP.apply();
620 return true;
621 }
622 if (DC3diffSETNP.isNameMatch(name))
623 {
624
625 DC3diffSETNP.setState(IPS_OK) ;
626 if (DC3diffSETNP.getState() == IPS_OK)
627 DC3diffSETNP.update(values, names, n);
628 DC3diffSETNP.apply();
629 return true;
630 }
631 if (DC3constSETNP.isNameMatch(name))
632 {
633
634 DC3constSETNP.setState(IPS_OK) ;
635 if (DC3constSETNP.getState() == IPS_OK)
636 DC3constSETNP.update(values, names, n);
637 DC3constSETNP.apply();
638 return true;
639 }
640
641 // DC2voltageSET
642 if (setDC2voltageNP.isNameMatch(name))
643 {
644 bool rc1 = false;
645 for (int i = 0; i < n; i++)
646 {
647 rc1 = setDewPWM(20, static_cast<uint8_t>(10*values[i]));
648 }
649
650 setDC2voltageNP.setState( (rc1) ? IPS_OK : IPS_ALERT);
651 if (setDC2voltageNP.getState() == IPS_OK)
652 setDC2voltageNP.update(values, names, n);
653 setDC2voltageNP.apply();
654 return true;
655 }
656
657
658 }
659 return INDI::DefaultDevice::ISNewNumber(dev, name, values, names, n);
660}
661
662bool WandererBoxPlusV3::setDewPWM(uint8_t id, uint8_t value)
663{
664 char cmd[64] = {0};
665 snprintf(cmd, 64, "%d%03d", id, value);
666 if (sendCommand(cmd))
667 {
668 return true;
669 }
670
671 return false;
672}
673
675{
676 return "WandererBox Pro V3";
677}
678
679
680bool WandererBoxPlusV3::sendCommand(std::string command)
681{
682 int nbytes_written = 0, rc = -1;
683 std::string command_termination = "\n";
684 LOGF_DEBUG("CMD: %s", command.c_str());
685 if ((rc = tty_write_string(PortFD, (command + command_termination).c_str(), &nbytes_written)) != TTY_OK)
686 {
687 char errorMessage[MAXRBUF];
688 tty_error_msg(rc, errorMessage, MAXRBUF);
689 LOGF_ERROR("Serial write error: %s", errorMessage);
690 return false;
691 }
692 return true;
693}
694
696{
697 if (!isConnected())
698 {
699 SetTimer(2500);
700 return;
701 }
702
703 getData();
704 SetTimer(2500);
705}
706
708{
711
712 DC3diffSP.save(fp);
713 DC3diffSETNP.save(fp);
714 DC3constSETNP.save(fp);
715 DC3ControlNP.save(fp);
716
717 setDC2voltageNP.save(fp);
718 return true;
719}
720
722{
723 // Weather is updated in updateENV() which is called from getData()
724 // This method is required by WeatherInterface but we update weather
725 // synchronously with sensor data, so we just return OK
726 return IPS_OK;
727}
728
double dewPoint
void registerHandshake(std::function< bool()> callback)
registerHandshake Register a handshake function to be called once the initial connection to the devic...
The Serial class manages connection with serial devices including Bluetooth. Serial communication is ...
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
bool isConnected() const
const char * getDeviceName() const
virtual bool updateProperties()
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
void registerConnection(Connection::Interface *newConnection)
registerConnection Add new connection plugin to the existing connection pool. The connection type sha...
void setDriverInterface(uint32_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
virtual bool saveConfigItems(FILE *fp)
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool initProperties()
Initialize properties initial state and value. The child class must implement this function.
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void save(FILE *f) const
save Save property to configuration file.
bool isNameMatch(const char *otherName) const
bool update(const double values[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
bool update(const ISState states[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, ISRule rule, double timeout, IPState state)
void addParameter(std::string name, std::string label, double numMinOk, double numMaxOk, double percWarning, bool flipWarning=false)
Add a physical weather measurable parameter to the weather driver.
bool processSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process weather switch properties.
bool setCriticalParameter(std::string name)
setCriticalParameter Set parameter that is considered critical to the operation of the observatory....
bool syncCriticalParameters()
Synchronize and update the state of all critical parameters.
void setParameterValue(std::string name, double value)
setParameterValue Update weather parameter value
bool processNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process weather number properties.
virtual bool saveConfigItems(FILE *fp)
saveConfigItems Save parameters ranges in the config file.
INDI::PropertyNumber ParametersNP
void initProperties(const char *statusGroup, const char *paramsGroup)
Initialize focuser properties. It is recommended to call this function within initProperties() of you...
bool updateProperties()
updateProperties Define or Delete Rotator properties based on the connection status of the base devic...
INDI::PropertyLight critialParametersLP
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual IPState updateWeather() override
updateWeather Update weather conditions from device or service. The function should not change the st...
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
const char * getDefaultName() override
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
ISState
Switch state.
Definition indiapi.h:148
@ ISS_OFF
Definition indiapi.h:149
@ ISS_ON
Definition indiapi.h:150
@ IP_RW
Definition indiapi.h:184
@ IP_RO
Definition indiapi.h:182
IPState
Property state.
Definition indiapi.h:158
@ IPS_ALERT
Definition indiapi.h:162
@ IPS_IDLE
Definition indiapi.h:159
@ IPS_OK
Definition indiapi.h:160
@ ISR_1OFMANY
Definition indiapi.h:171
@ ISR_ATMOST1
Definition indiapi.h:172
int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition indicom.c:653
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition indicom.c:473
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition indicom.c:1243
Implementations for common driver routines.
@ TTY_OK
Definition indicom.h:54
#define MAXRBUF
Definition indidriver.c:52
#define LOGF_INFO(fmt,...)
Definition indilogger.h:82
#define LOGF_DEBUG(fmt,...)
Definition indilogger.h:83
#define LOGF_ERROR(fmt,...)
Definition indilogger.h:80
#define LOG_INFO(txt)
Definition indilogger.h:74
Namespace to encapsulate INDI client, drivers, and mediator classes.
uint8_t cmd[4]
Definition pwc-ioctl.h:2