Instrument Neutral Distributed Interface INDI 2.2.5
wanderer_dew_terminator.cpp
Go to the documentation of this file.
1/*******************************************************************************
2 Copyright(c) 2024 Frank Wang. All rights reserved.
3
4 Wanderer Dew Terminator
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
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
37// We declare an auto pointer to WandererDewTerminator.
38static std::unique_ptr<WandererDewTerminator> wandererdewterminator(new WandererDewTerminator());
39
40
41
46
48{
49
52
53
55
56
57
58
59 // Power Monitor
60 PowerMonitorNP[VOLTAGE].fill("VOLTAGE", "Voltage (V)", "%4.2f", 0, 999, 100, 0);
61
62 PowerMonitorNP.fill(getDeviceName(), "POWER_Monitor", "Power Monitor", MAIN_CONTROL_TAB, IP_RO,60, IPS_IDLE);
63
64
65
66
67 // DC123
68
69
70 DC1ControlNP[DC1].fill( "DC1", "Dew Heater (PWM)", "%.2f", 0, 255, 5, 0);
71 DC1ControlNP.fill(getDeviceName(), "PWM", "DC1", DC1_TAB, IP_RW, 60, IPS_IDLE);
72
73 DC2ControlNP[DC2].fill( "DC2", "Dew Heater (PWM)", "%.2f", 0, 255, 5, 0);
74 DC2ControlNP.fill( getDeviceName(), "DC2", "DC2", DC2_TAB, IP_RW, 60, IPS_IDLE);
75
76 DC3ControlNP[DC3].fill( "DC3", "Dew Heater (PWM)", "%.2f", 0, 255, 5, 0);
77 DC3ControlNP.fill(getDeviceName(), "DC3", "DC3", DC3_TAB, IP_RW, 60, IPS_IDLE);
78
79
80 // DC1 TEMP Difference Control
81 DC1diffSP[DC1_Manual].fill( "Manual", "Manual", ISS_ON);
82 DC1diffSP[DC1_DPD_Mode].fill( "DPD_Mode", "DPD Mode", ISS_OFF);
83 DC1diffSP[DC1_CT_Mode].fill( "CT_Mode", "CT Mode", ISS_OFF);
84 DC1diffSP.fill(getDeviceName(), "DC1_DIFF", "DC1 Dew Mode", DC1_TAB, IP_RW,ISR_1OFMANY, 60, IPS_IDLE);
85
86 DC1diffSETNP[DC1DIFFSET].fill( "DC1 Auto Control", "Dew Point Difference(C)", "%.2f", 10, 30, 1, 0);
87 DC1diffSETNP.fill(getDeviceName(), "DC1_DIFF_SET", "DPD Mode", DC1_TAB, IP_RW, 60, IPS_IDLE);
88
89 DC1constSETNP[DC1CONSTSET].fill( "DC1 Auto Control", "Temperature(C)", "%.2f", 0, 40, 1, 0);
90 DC1constSETNP.fill(getDeviceName(), "DC1_CONST_SET", "CT Mode", DC1_TAB, IP_RW, 60, IPS_IDLE);
91
92 // DC2 TEMP Difference Control
93 DC2diffSP[DC2_Manual].fill( "Manual", "Manual", ISS_ON);
94 DC2diffSP[DC2_DPD_Mode].fill( "DPD_Mode", "DPD Mode", ISS_OFF);
95 DC2diffSP[DC2_CT_Mode].fill( "CT_Mode", "CT Mode", ISS_OFF);
96 DC2diffSP.fill(getDeviceName(), "DC2_DIFF", "DC2 Dew Mode", DC2_TAB, IP_RW,ISR_1OFMANY, 60, IPS_IDLE);
97
98 DC2diffSETNP[DC2DIFFSET].fill( "DC2 Auto Control", "Dew Point Difference(C)", "%.2f", 10, 30, 1, 0);
99 DC2diffSETNP.fill(getDeviceName(), "DC2_DIFF_SET", "DPD Mode", DC2_TAB, IP_RW, 60, IPS_IDLE);
100
101 DC2constSETNP[DC2CONSTSET].fill( "DC2 Auto Control", "Temperature(C)", "%.2f", 0, 40, 1, 0);
102 DC2constSETNP.fill(getDeviceName(), "DC2_CONST_SET", "CT Mode", DC2_TAB, IP_RW, 60, IPS_IDLE);
103
104 // DC3 TEMP Difference Control
105 DC3diffSP[DC3_Manual].fill( "Manual", "Manual", ISS_ON);
106 DC3diffSP[DC3_DPD_Mode].fill( "DPD_Mode", "DPD Mode", ISS_OFF);
107 DC3diffSP[DC3_CT_Mode].fill( "CT_Mode", "CT Mode", ISS_OFF);
108 DC3diffSP.fill(getDeviceName(), "DC3_DIFF", "DC3 Dew Mode", DC3_TAB, IP_RW,ISR_1OFMANY, 60, IPS_IDLE);
109
110 DC3diffSETNP[DC3DIFFSET].fill( "DC3 Auto Control", "Dew Point Difference(C)", "%.2f", 10, 30, 1, 0);
111 DC3diffSETNP.fill(getDeviceName(), "DC3_DIFF_SET", "DPD Mode", DC3_TAB, IP_RW, 60, IPS_IDLE);
112
113 DC3constSETNP[DC3CONSTSET].fill( "DC3 Auto Control", "Temperature(C)", "%.2f", 0, 40, 1, 0);
114 DC3constSETNP.fill(getDeviceName(), "DC3_CONST_SET", "CT Mode", DC3_TAB, IP_RW, 60, IPS_IDLE);
115
116 //ENV
117 ENVMonitorNP[Probe1_Temp].fill( "Probe1_Temp", "Probe1 Temperature (C)", "%4.2f", 0, 999, 100, 0);
118 ENVMonitorNP[Probe2_Temp].fill( "Probe2_Temp", "Probe2 Temperature (C)", "%4.2f", 0, 999, 100, 0);
119 ENVMonitorNP[Probe3_Temp].fill( "Probe3_Temp", "Probe3 Temperature (C)", "%4.2f", 0, 999, 100, 0);
120 ENVMonitorNP[ENV_Humidity].fill( "ENV_Humidity", "Ambient Humidity %", "%4.2f", 0, 999, 100, 0);
121 ENVMonitorNP[ENV_Temp].fill( "ENV_Temp", "Ambient Temperature (C)", "%4.2f", 0, 999, 100, 0);
122 ENVMonitorNP[DEW_Point].fill( "DEW_Point", "Dew Point (C)", "%4.2f", 0, 999, 100, 0);
123 ENVMonitorNP.fill(getDeviceName(), "ENV_Monitor", "Environment",ENVIRONMENT_TAB, IP_RO,60, IPS_IDLE);
124 serialConnection = new Connection::Serial(this);
126 serialConnection->registerHandshake([&]()
127 {
128 return getData();
129 });
130 registerConnection(serialConnection);
131
132 return true;
133}
134
135bool WandererDewTerminator::getData()
136{
137 try
138 {
139 PortFD = serialConnection->getPortFD();
140 tcflush(PortFD, TCIOFLUSH);
141 int nbytes_read_name = 0,rc=-1;
142 char name[64] = {0};
143
144 //Device Model//////////////////////////////////////////////////////////////////////////////////////////////////////
145 if ((rc = tty_read_section(PortFD, name, 'A', 3, &nbytes_read_name)) != TTY_OK)
146 {
147 char errorMessage[MAXRBUF];
148 tty_error_msg(rc, errorMessage, MAXRBUF);
149 LOGF_INFO("No data received, the device may not be Wanderer Dew Terminator, please check the serial port!","Updated");
150 LOGF_ERROR("Device read error: %s", errorMessage);
151 return false;
152 }
153 name[nbytes_read_name - 1] = '\0';
154 if(strcmp(name, "ZXWBPlusV3")==0||strcmp(name, "WandererCoverV4")==0||strcmp(name, "UltimateV2")==0||strcmp(name, "PlusV2")==0||strcmp(name, "ZXWBProV3")==0)
155 {
156 LOGF_INFO("The device is not Wanderer Dew Terminator!","Updated");
157 return false;
158 }
159 if(strcmp(name, "ZXWBDewTerminator")!=0)
160 throw std::exception();
161 // Frimware version/////////////////////////////////////////////////////////////////////////////////////////////
162 int nbytes_read_version = 0;
163 char version[64] = {0};
164 tty_read_section(PortFD, version, 'A', 5, &nbytes_read_version);
165
166 version[nbytes_read_version - 1] = '\0';
167 firmware=std::atoi(version);
168
169
170 // Temp probe 1//////////////////////////////////////////////////////////////////////////////////////////
171 char temp1[64] = {0};
172 int nbytes_read_temp1= 0;
173 tty_read_section(PortFD, temp1, 'A', 5, &nbytes_read_temp1);
174 temp1[nbytes_read_temp1 - 1] = '\0';
175 temp1read = std::strtod(temp1,NULL);
176
177 // Temp probe 2//////////////////////////////////////////////////////////////////////////////////////////
178 char temp2[64] = {0};
179 int nbytes_read_temp2= 0;
180 tty_read_section(PortFD, temp2, 'A', 5, &nbytes_read_temp2);
181 temp2[nbytes_read_temp2 - 1] = '\0';
182 temp2read = std::strtod(temp2,NULL);
183
184 // Temp probe 3//////////////////////////////////////////////////////////////////////////////////////////
185 char temp3[64] = {0};
186 int nbytes_read_temp3= 0;
187 tty_read_section(PortFD, temp3, 'A', 5, &nbytes_read_temp3);
188 temp3[nbytes_read_temp3 - 1] = '\0';
189 temp3read = std::strtod(temp3,NULL);
190
191 // DHTH//////////////////////////////////////////////////////////////////////////////////////////
192 char DHTH[64] = {0};
193 int nbytes_read_DHTH= 0;
194 tty_read_section(PortFD, DHTH, 'A', 5, &nbytes_read_DHTH);
195 DHTH[nbytes_read_DHTH - 1] = '\0';
196 DHTHread = std::strtod(DHTH,NULL);
197
198 // DHTT//////////////////////////////////////////////////////////////////////////////////////////
199 char DHTT[64] = {0};
200 int nbytes_read_DHTT= 0;
201 tty_read_section(PortFD, DHTT, 'A', 5, &nbytes_read_DHTT);
202 DHTT[nbytes_read_DHTT - 1] = '\0';
203 DHTTread = std::strtod(DHTT,NULL);
204 updateENV(temp1read,temp2read,temp3read,DHTHread,DHTTread);
205
206
207
208 // Voltage//////////////////////////////////////////////////////////////////////////////////////////
209 char voltage[64] = {0};
210 int nbytes_read_voltage= 0;
211 tty_read_section(PortFD, voltage, 'A', 5, &nbytes_read_voltage);
212 voltage[nbytes_read_voltage - 1] = '\0';
213 voltageread = std::strtod(voltage,NULL);
214 updatePower(voltageread);
215
216
217
218 // DC1//////////////////////////////////////////////////////////////////////////////////////////
219 char DC1[64] = {0};
220 int nbytes_read_DC1= 0;
221 tty_read_section(PortFD, DC1, 'A', 5, &nbytes_read_DC1);
222 DC1[nbytes_read_DC1 - 1] = '\0';
223 DC1read = std::stoi(DC1);
224 updateDC1(DC1read);
225
226 // DC2//////////////////////////////////////////////////////////////////////////////////////////
227 char DC2[64] = {0};
228 int nbytes_read_DC2= 0;
229 tty_read_section(PortFD, DC2, 'A', 5, &nbytes_read_DC2);
230 DC2[nbytes_read_DC2 - 1] = '\0';
231 DC2read = std::stoi(DC2);
232 updateDC2(DC2read);
233
234 // DC3//////////////////////////////////////////////////////////////////////////////////////////
235 char DC3[64] = {0};
236 int nbytes_read_DC3= 0;
237 tty_read_section(PortFD, DC3, 'A', 5, &nbytes_read_DC3);
238 DC3[nbytes_read_DC3 - 1] = '\0';
239 DC3read = std::stoi(DC3);
240 updateDC3(DC3read);
241
242
243
244
245 //DC1 DEW CONTROL
246 if(DC1diffSP[DC1_DPD_Mode].getState() == ISS_ON)
247 {
248 if(temp1read<ENVMonitorNP[DEW_Point].value+DC1diffSETNP[DC1DIFFSET].value)
249 sendCommand("5255");
250 else
251 sendCommand("5000");
252 }
253
254 if(DC1CONSTMODE==true )
255 {
256 if(temp1read<DC1constSETNP[DC1CONSTSET].value)
257 sendCommand("5255");
258 else
259 sendCommand("5000");
260 }
261 if (DC1diffSP[DC1_DPD_Mode].getState() == ISS_ON&&ENVMonitorNP[Probe1_Temp].value==-127)
262 {
263 DC1DIFFMODE=false;
264 DC1CONSTMODE=false;
265 defineProperty(DC1ControlNP);
266 deleteProperty(DC1diffSETNP);
267 deleteProperty(DC1constSETNP);
268 LOGF_ERROR("Temp probe 1 not connected, Dew Point Difference Mode for DC1 has exited!","Updated");
269 LOGF_INFO("You need to insert the probe firmly to the end!","Updated");
270 DC1diffSP[DC1_Manual].setState( ISS_ON);
271 DC1diffSP[DC1_DPD_Mode].setState( ISS_OFF);
272 DC1diffSP[DC1_CT_Mode].setState( ISS_OFF);
273 DC1diffSP.setState(IPS_OK);
274 DC1diffSP.apply();
275 }
276 if (DC1diffSP[DC1_DPD_Mode].getState() == ISS_ON&&isnan(ENVMonitorNP[DEW_Point].value)==1)
277 {
278 DC1DIFFMODE=false;
279 DC1CONSTMODE=false;
280 defineProperty(DC1ControlNP);
281 deleteProperty(DC1diffSETNP);
282 deleteProperty(DC1constSETNP);
283 LOGF_ERROR("DHT22 Humidity&Temperature sensor not connected, Dew Point Difference Mode for DC1 has exited!","Updated");
284 DC1diffSP[DC1_Manual].setState( ISS_ON);
285 DC1diffSP[DC1_DPD_Mode].setState( ISS_OFF);
286 DC1diffSP[DC1_CT_Mode].setState( ISS_OFF);
287 DC1diffSP.setState(IPS_OK);
288 DC1diffSP.apply();
289 }
290 if (DC1diffSP[DC1_CT_Mode].getState() == ISS_ON&&ENVMonitorNP[Probe1_Temp].value==-127)
291 {
292 DC1DIFFMODE=false;
293 DC1CONSTMODE=false;
294 defineProperty(DC1ControlNP);
295 deleteProperty(DC1diffSETNP);
296 deleteProperty(DC1constSETNP);
297 LOGF_ERROR("Temp probe 1 not connected, Constant Temperature Mode for DC1 has exited!","Updated");
298 LOGF_INFO("You need to insert the probe firmly to the end!","Updated");
299 DC1diffSP[DC1_Manual].setState( ISS_ON);
300 DC1diffSP[DC1_DPD_Mode].setState( ISS_OFF);
301 DC1diffSP[DC1_CT_Mode].setState( ISS_OFF);
302 DC1diffSP.setState(IPS_OK);
303 DC1diffSP.apply();
304 }
305
306
307
308 //DC2 DEW CONTROL
309 if(DC2DIFFMODE==true )
310 {
311 if(temp2read<ENVMonitorNP[DEW_Point].value+DC2diffSETNP[DC2DIFFSET].value)
312 sendCommand("6255");
313 else
314 sendCommand("6000");
315 }
316 if(DC2CONSTMODE==true )
317 {
318 if(temp2read<DC2constSETNP[DC2CONSTSET].value)
319 sendCommand("6255");
320 else
321 sendCommand("6000");
322 }
323 if (DC2diffSP[DC2_DPD_Mode].getState() == ISS_ON&&ENVMonitorNP[Probe2_Temp].value==-127)
324 {
325 DC2DIFFMODE=false;
326 DC2CONSTMODE=false;
327 defineProperty(DC2ControlNP);
328 deleteProperty(DC2diffSETNP);
329 deleteProperty(DC2constSETNP);
330 LOGF_ERROR("Temp probe 2 not connected, Dew Point Difference Mode for DC2 has exited!","Updated");
331 LOGF_INFO("You need to insert the probe firmly to the end!","Updated");
332 DC2diffSP[DC2_Manual].setState( ISS_ON);
333 DC2diffSP[DC2_DPD_Mode].setState( ISS_OFF);
334 DC2diffSP[DC2_CT_Mode].setState( ISS_OFF);
335 DC2diffSP.setState(IPS_OK);
336 DC2diffSP.apply();
337 }
338 if (DC2diffSP[DC2_DPD_Mode].getState() == ISS_ON&&isnan(ENVMonitorNP[DEW_Point].value)==1)
339 {
340 DC2DIFFMODE=false;
341 DC2CONSTMODE=false;
342 defineProperty(DC2ControlNP);
343 deleteProperty(DC2diffSETNP);
344 deleteProperty(DC2constSETNP);
345 LOGF_ERROR("DHT22 Humidity&Temperature sensor not connected, Dew Point Difference Mode for DC2 has exited!","Updated");
346 DC2diffSP[DC2_Manual].setState( ISS_ON);
347 DC2diffSP[DC2_DPD_Mode].setState( ISS_OFF);
348 DC2diffSP[DC2_CT_Mode].setState( ISS_OFF);
349 DC2diffSP.setState(IPS_OK);
350 DC2diffSP.apply();
351 }
352 if (DC2diffSP[DC2_CT_Mode].getState() == ISS_ON&&ENVMonitorNP[Probe2_Temp].value==-127)
353 {
354 DC2DIFFMODE=false;
355 DC2CONSTMODE=false;
356 defineProperty(DC2ControlNP);
357 deleteProperty(DC2diffSETNP);
358 deleteProperty(DC2constSETNP);
359 LOGF_ERROR("Temp probe 2 not connected, Constant Temperature Mode for DC2 has exited!","Updated");
360 LOGF_INFO("You need to insert the probe firmly to the end!","Updated");
361 DC2diffSP[DC2_Manual].setState( ISS_ON);
362 DC2diffSP[DC2_DPD_Mode].setState( ISS_OFF);
363 DC2diffSP[DC2_CT_Mode].setState( ISS_OFF);
364 DC2diffSP.setState(IPS_OK);
365 DC2diffSP.apply();
366 }
367
368
369 //DC3 DEW CONTROL
370 if(DC3DIFFMODE==true )
371 {
372 if(temp3read<ENVMonitorNP[DEW_Point].value+DC3diffSETNP[DC3DIFFSET].value)
373 sendCommand("7255");
374 else
375 sendCommand("7000");
376 }
377 if(DC3CONSTMODE==true )
378 {
379 if(temp3read<DC3constSETNP[DC3CONSTSET].value)
380 sendCommand("7255");
381 else
382 sendCommand("7000");
383 }
384 if (DC3diffSP[DC3_DPD_Mode].getState() == ISS_ON&&ENVMonitorNP[Probe3_Temp].value==-127)
385 {
386 DC3DIFFMODE=false;
387 DC3CONSTMODE=false;
388 defineProperty(DC3ControlNP);
389 deleteProperty(DC3diffSETNP);
390 deleteProperty(DC3constSETNP);
391 LOGF_ERROR("Temp probe 3 not connected, Dew Point Difference Mode for DC3 has exited!","Updated");
392 LOGF_INFO("You need to insert the probe firmly to the end!","Updated");
393 DC3diffSP[DC3_Manual].setState( ISS_ON);
394 DC3diffSP[DC3_DPD_Mode].setState( ISS_OFF);
395 DC3diffSP[DC3_CT_Mode].setState( ISS_OFF);
396 DC3diffSP.setState(IPS_OK);
397 DC3diffSP.apply();
398 }
399 if (DC3diffSP[DC3_DPD_Mode].getState() == ISS_ON&&isnan(ENVMonitorNP[DEW_Point].value)==1)
400 {
401 DC3DIFFMODE=false;
402 DC3CONSTMODE=false;
403 defineProperty(DC3ControlNP);
404 deleteProperty(DC3diffSETNP);
405 deleteProperty(DC3constSETNP);
406 LOGF_ERROR("DHT22 Humidity&Temperature sensor not connected, Dew Point Difference Mode for DC3 has exited!","Updated");
407 DC3diffSP[DC3_Manual].setState( ISS_ON);
408 DC3diffSP[DC3_DPD_Mode].setState( ISS_OFF);
409 DC3diffSP[DC3_CT_Mode].setState( ISS_OFF);
410 DC3diffSP.setState(IPS_OK);
411 DC3diffSP.apply();
412 }
413 if (DC3diffSP[DC3_CT_Mode].getState() == ISS_ON&&ENVMonitorNP[Probe3_Temp].value==-127)
414 {
415 DC3DIFFMODE=false;
416 DC3CONSTMODE=false;
417 defineProperty(DC3ControlNP);
418 deleteProperty(DC3diffSETNP);
419 deleteProperty(DC3constSETNP);
420 LOGF_ERROR("Temp probe 3 not connected, Constant Temperature Mode for DC3 has exited!","Updated");
421 LOGF_INFO("You need to insert the probe firmly to the end!","Updated");
422 DC3diffSP[DC3_Manual].setState( ISS_ON);
423 DC3diffSP[DC3_DPD_Mode].setState( ISS_OFF);
424 DC3diffSP[DC3_CT_Mode].setState( ISS_OFF);
425 DC3diffSP.setState(IPS_OK);
426 DC3diffSP.apply();
427 }
428
429 }
430 catch(std::exception& e)
431 {
432 //LOGF_INFO("Data read failed","failed");
433 }
434 return true;
435}
436
437
438
439void WandererDewTerminator::updateENV(double temp1,double temp2,double temp3,double DHTH,double DHTT)
440{
441 ENVMonitorNP[Probe1_Temp].setValue(temp1);
442 ENVMonitorNP[Probe2_Temp].setValue(temp2);
443 ENVMonitorNP[Probe3_Temp].setValue(temp3);
444 ENVMonitorNP[ENV_Humidity].setValue(DHTH);
445 ENVMonitorNP[ENV_Temp].setValue(DHTT);
446 ENVMonitorNP[DEW_Point].setValue((237.7 * ((17.27 * DHTT) / (237.7 + DHTT) + log((DHTH / 100)))) / (17.27 - ((17.27 * DHTT) / (237.7 + DHTT) + log((DHTH / 100)))));;
447 ENVMonitorNP.setState(IPS_OK);
448 ENVMonitorNP.apply();
449
450}
451
452
453void WandererDewTerminator::updatePower(double voltage)
454{
455 // Power Monitor
456 PowerMonitorNP[VOLTAGE].setValue(voltage);
457
458 PowerMonitorNP.setState(IPS_OK);
459 PowerMonitorNP.apply();
460}
461
462
463void WandererDewTerminator::updateDC1(int res)
464{
465 DC1ControlNP[0].setValue(res);
466 DC1ControlNP.setState(IPS_OK);
467 DC1ControlNP.apply();
468}
469
470void WandererDewTerminator::updateDC2(int res)
471{
472 DC2ControlNP[0].setValue(res);
473 DC2ControlNP.setState(IPS_OK);
474 DC2ControlNP.apply();
475}
476
477void WandererDewTerminator::updateDC3(int res)
478{
479 DC3ControlNP[0].setValue(res);
480 DC3ControlNP.setState(IPS_OK);
481 DC3ControlNP.apply();
482}
483
484
485
486
487
489{
491
492 if (isConnected())
493 {
494
495 if(firmware>=20240410)
496 {
497
498 LOGF_INFO("Firmware version: %d", firmware);
499 }
500 else
501 {
502 LOGF_INFO("The firmware is outdated, please upgrade to the latest firmware, or power reading calibration will be unavailable.","failed");
503 }
504 defineProperty(PowerMonitorNP);
505
506
507
508
509 defineProperty(DC1diffSP);
510 defineProperty(DC2diffSP);
511 defineProperty(DC3diffSP);
512
513
514 //DC1////////////////////
515 if(DC1diffSP[DC1_DPD_Mode].getState() == ISS_ON)
516 {
517 deleteProperty(DC1constSETNP);
518 deleteProperty(DC1ControlNP);
519 defineProperty(DC1diffSETNP);
520 }
521 else if(DC1diffSP[DC1_CT_Mode].getState() == ISS_ON)
522 {
523 deleteProperty(DC1ControlNP);
524 deleteProperty(DC1diffSETNP);
525 defineProperty(DC1constSETNP);
526 }
527 else
528 {
529 defineProperty(DC1ControlNP);
530 deleteProperty(DC1diffSETNP);
531 deleteProperty(DC1constSETNP);
532 }
533 //DC2////////////////
534 if(DC2diffSP[DC2_DPD_Mode].getState() == ISS_ON)
535 {
536 deleteProperty(DC2constSETNP);
537 deleteProperty(DC2ControlNP);
538 defineProperty(DC2diffSETNP);
539 }
540 else if(DC2diffSP[DC2_CT_Mode].getState() == ISS_ON)
541 {
542 deleteProperty(DC2ControlNP);
543 deleteProperty(DC2diffSETNP);
544 defineProperty(DC2constSETNP);
545 }
546 else
547 {
548 defineProperty(DC2ControlNP);
549 deleteProperty(DC2diffSETNP);
550 deleteProperty(DC2constSETNP);
551 }
552 //DC3////////////////
553 if(DC3diffSP[DC3_DPD_Mode].getState() == ISS_ON)
554 {
555 deleteProperty(DC3constSETNP);
556 deleteProperty(DC3ControlNP);
557 defineProperty(DC3diffSETNP);
558 }
559 else if(DC3diffSP[DC3_CT_Mode].getState() == ISS_ON)
560 {
561 deleteProperty(DC3ControlNP);
562 deleteProperty(DC3diffSETNP);
563 defineProperty(DC3constSETNP);
564 }
565 else
566 {
567 defineProperty(DC3ControlNP);
568 deleteProperty(DC3diffSETNP);
569 deleteProperty(DC3constSETNP);
570 }
571
572
573 defineProperty(ENVMonitorNP);
574
575
576 }
577 else
578 {
579
580
581 deleteProperty(PowerMonitorNP);
582 deleteProperty(ENVMonitorNP);
583
584
585
586 deleteProperty(DC1ControlNP);
587 deleteProperty(DC2ControlNP);
588 deleteProperty(DC3ControlNP);
589
590 deleteProperty(DC1diffSP);
591 deleteProperty(DC1diffSETNP);
592
593 deleteProperty(DC2diffSP);
594 deleteProperty(DC2diffSETNP);
595
596 deleteProperty(DC3diffSP);
597 deleteProperty(DC3diffSETNP);
598
599
600 }
601 return true;
602}
603
604bool WandererDewTerminator::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
605{
606
607
608 // DC1 DEW
609 if (DC1diffSP.isNameMatch(name))
610 {
611 DC1diffSP.update(states, names, n);
612 DC1diffSP.setState(IPS_ALERT);
613 if(DC1diffSP[DC1_DPD_Mode].getState() == ISS_ON&&ENVMonitorNP[Probe1_Temp].value!=-127&&isnan(ENVMonitorNP[DEW_Point].value)==0)
614 {
615 DC1DIFFMODE=true;
616 DC1CONSTMODE=false;
617 deleteProperty(DC1ControlNP);
618 deleteProperty(DC1constSETNP);
619 defineProperty(DC1diffSETNP);
620
621 DC1diffSETNP.setState(IPS_OK);
622 DC1diffSETNP.apply();
623 DC1diffSP.setState(IPS_OK) ;
624 DC1diffSP.apply();
625 LOGF_INFO("Dew Point Difference Mode for DC1 activated! WandererBox will keep the dew heater at the temperature higher than the dew point by the set value.","Updated");
626 return true;
627 }
628 else if(DC1diffSP[DC1_DPD_Mode].getState() == ISS_ON&&(ENVMonitorNP[Probe1_Temp].value==-127||isnan(ENVMonitorNP[DEW_Point].value)==1))
629 {
630 DC1DIFFMODE=false;
631 DC1CONSTMODE=false;
632 DC1diffSP[DC1_Manual].setState( ISS_ON);
633 LOGF_INFO("Manual Mode for DC1 activated! Please adjust the duty cycle manually, you can also use DC1 as an ordinary switch.","Updated");
634 DC1diffSP.apply();
635 }
636 else if(DC1diffSP[DC1_CT_Mode].getState() == ISS_ON&&ENVMonitorNP[Probe1_Temp].value!=-127)
637 {
638 DC1CONSTMODE=true;
639 DC1DIFFMODE=false;
640 deleteProperty(DC1diffSETNP);
641 deleteProperty(DC1ControlNP);
642 defineProperty(DC1constSETNP);
643
644 DC1constSETNP.setState(IPS_OK);
645 DC1constSETNP.apply();
646 DC1diffSP.setState(IPS_OK) ;
647 DC1diffSP.apply();
648 LOGF_INFO("Constant Temperature Mode for DC1 activated! WandererBox will keep the dew heater at the set temperature.","Updated");
649 return true;
650 }
651 else if(DC1diffSP[DC1_CT_Mode].getState() == ISS_ON&&ENVMonitorNP[Probe1_Temp].value==-127)
652 {
653 DC1DIFFMODE=false;
654 DC1CONSTMODE=false;
655 DC1diffSP[DC1_Manual].setState( ISS_ON);
656 LOGF_INFO("Manual Mode for DC1 activated! Please adjust the duty cycle manually, you can also use DC1 as an ordinary switch.","Updated");
657 DC1diffSP.apply();
658 }
659 else
660 {
661 DC1DIFFMODE=false;
662 DC1CONSTMODE=false;
663 defineProperty(DC1ControlNP);
664 deleteProperty(DC1diffSETNP);
665 deleteProperty(DC1constSETNP);
666 DC1diffSP.setState(IPS_OK) ;
667 DC1diffSP.apply();
668 LOGF_INFO("Manual Mode for DC1 activated! Please adjust the duty cycle manually, you can also use DC1 as an ordinary switch.","Updated");
669 return true;
670 }
671
672 }
673
674 // DC2 DEW
675 if (DC2diffSP.isNameMatch(name))
676 {
677 DC2diffSP.update(states, names, n);
678 DC2diffSP.setState(IPS_ALERT);
679 if(DC2diffSP[DC2_DPD_Mode].getState() == ISS_ON&&ENVMonitorNP[Probe2_Temp].value!=-127&&isnan(ENVMonitorNP[DEW_Point].value)==0)
680 {
681 DC2DIFFMODE=true;
682 DC2CONSTMODE=false;
683 deleteProperty(DC2ControlNP);
684 deleteProperty(DC2constSETNP);
685 defineProperty(DC2diffSETNP);
686
687 DC2diffSETNP.setState(IPS_OK);
688 DC2diffSETNP.apply();
689 DC2diffSP.setState(IPS_OK) ;
690 DC2diffSP.apply();
691 LOGF_INFO("Dew Point Difference Mode for DC2 activated! WandererBox will keep the dew heater at the temperature higher than the dew point by the set value.","Updated");
692 return true;
693 }
694 else if(DC2diffSP[DC2_DPD_Mode].getState() == ISS_ON&&(ENVMonitorNP[Probe2_Temp].value==-127||isnan(ENVMonitorNP[DEW_Point].value)==1))
695 {
696 DC2DIFFMODE=false;
697 DC2CONSTMODE=false;
698 DC2diffSP[DC2_Manual].setState( ISS_ON);
699 LOGF_INFO("Manual Mode for DC2 activated! Please adjust the duty cycle manually, you can also use DC2 as an ordinary switch.","Updated");
700 DC2diffSP.apply();
701 }
702 else if(DC2diffSP[DC2_CT_Mode].getState() == ISS_ON&&ENVMonitorNP[Probe2_Temp].value!=-127)
703 {
704 DC2CONSTMODE=true;
705 DC2DIFFMODE=false;
706 deleteProperty(DC2diffSETNP);
707 deleteProperty(DC2ControlNP);
708 defineProperty(DC2constSETNP);
709
710 DC2constSETNP.setState(IPS_OK);
711 DC2constSETNP.apply();
712 DC2diffSP.setState(IPS_OK) ;
713 DC2diffSP.apply();
714 LOGF_INFO("Constant Temperature Mode for DC2 activated! WandererBox will keep the dew heater at the set temperature.","Updated");
715 return true;
716 }
717 else if(DC2diffSP[DC2_CT_Mode].getState() == ISS_ON&&ENVMonitorNP[Probe2_Temp].value==-127)
718 {
719 DC2DIFFMODE=false;
720 DC2CONSTMODE=false;
721 DC2diffSP[DC2_Manual].setState( ISS_ON);
722 LOGF_INFO("Manual Mode for DC2 activated! Please adjust the duty cycle manually, you can also use DC2 as an ordinary switch.","Updated");
723 DC2diffSP.apply();
724 }
725 else
726 {
727 DC2DIFFMODE=false;
728 DC2CONSTMODE=false;
729 defineProperty(DC2ControlNP);
730 deleteProperty(DC2diffSETNP);
731 deleteProperty(DC2constSETNP);
732 DC2diffSP.setState(IPS_OK) ;
733 DC2diffSP.apply();
734 LOGF_INFO("Manual Mode for DC2 activated! Please adjust the duty cycle manually, you can also use DC2 as an ordinary switch.","Updated");
735 return true;
736 }
737
738 }
739
740 // DC3 DEW
741 if (DC3diffSP.isNameMatch(name))
742 {
743 DC3diffSP.update(states, names, n);
744 DC3diffSP.setState(IPS_ALERT);
745 if(DC3diffSP[DC3_DPD_Mode].getState() == ISS_ON&&ENVMonitorNP[Probe3_Temp].value!=-127&&isnan(ENVMonitorNP[DEW_Point].value)==0)
746 {
747 DC3DIFFMODE=true;
748 DC3CONSTMODE=false;
749 deleteProperty(DC3ControlNP);
750 deleteProperty(DC3constSETNP);
751 defineProperty(DC3diffSETNP);
752
753 DC3diffSETNP.setState(IPS_OK);
754 DC3diffSETNP.apply();
755 DC3diffSP.setState(IPS_OK) ;
756 DC3diffSP.apply();
757 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");
758 return true;
759 }
760 else if(DC3diffSP[DC3_DPD_Mode].getState() == ISS_ON&&(ENVMonitorNP[Probe3_Temp].value==-127||isnan(ENVMonitorNP[DEW_Point].value)==1))
761 {
762 DC3DIFFMODE=false;
763 DC3CONSTMODE=false;
764 DC3diffSP[DC3_Manual].setState( ISS_ON);
765 LOGF_INFO("Manual Mode for DC3 activated! Please adjust the duty cycle manually, you can also use DC3 as an ordinary switch.","Updated");
766 DC3diffSP.apply();
767 }
768 else if(DC3diffSP[DC3_CT_Mode].getState() == ISS_ON&&ENVMonitorNP[Probe3_Temp].value!=-127)
769 {
770 DC3CONSTMODE=true;
771 DC3DIFFMODE=false;
772 deleteProperty(DC3diffSETNP);
773 deleteProperty(DC3ControlNP);
774 defineProperty(DC3constSETNP);
775
776 DC3constSETNP.setState(IPS_OK);
777 DC3constSETNP.apply();
778 DC3diffSP.setState(IPS_OK) ;
779 DC3diffSP.apply();
780 LOGF_INFO("Constant Temperature Mode for DC3 activated! WandererBox will keep the dew heater at the set temperature.","Updated");
781 return true;
782 }
783 else if(DC3diffSP[DC3_CT_Mode].getState() == ISS_ON&&ENVMonitorNP[Probe3_Temp].value==-127)
784 {
785 DC3DIFFMODE=false;
786 DC3CONSTMODE=false;
787 DC3diffSP[DC3_Manual].setState( ISS_ON);
788 LOGF_INFO("Manual Mode for DC3 activated! Please adjust the duty cycle manually, you can also use DC3 as an ordinary switch.","Updated");
789 DC3diffSP.apply();
790 }
791 else
792 {
793 DC3DIFFMODE=false;
794 DC3CONSTMODE=false;
795 defineProperty(DC3ControlNP);
796 deleteProperty(DC3diffSETNP);
797 deleteProperty(DC3constSETNP);
798 DC3diffSP.setState(IPS_OK) ;
799 DC3diffSP.apply();
800 LOGF_INFO("Manual Mode for DC3 activated! Please adjust the duty cycle manually, you can also use DC3 as an ordinary switch.","Updated");
801 return true;
802 }
803
804 }
805
806 return DefaultDevice::ISNewSwitch(dev, name, states, names, n);
807}
808
809bool WandererDewTerminator::ISNewNumber(const char * dev, const char * name, double values[], char * names[], int n)
810{
811 if (dev && !strcmp(dev, getDeviceName()))
812 {
813 // DC1
814 if (DC1ControlNP.isNameMatch(name))
815 {
816 bool rc1 = false;
817 for (int i = 0; i < n; i++)
818 {
819 rc1 = setDewPWM(5, static_cast<uint8_t>(values[i]));
820 }
821
822 DC1ControlNP.setState( (rc1) ? IPS_OK : IPS_ALERT);
823 if (DC1ControlNP.getState() == IPS_OK)
824 DC1ControlNP.update(values, names, n);
825 DC1ControlNP.apply();
826 return true;
827 }
828 if (DC1diffSETNP.isNameMatch(name))
829 {
830
831 DC1diffSETNP.setState(IPS_OK) ;
832 if (DC1diffSETNP.getState() == IPS_OK)
833 DC1diffSETNP.update(values, names, n);
834 DC1diffSETNP.apply();
835 return true;
836 }
837 if (DC1constSETNP.isNameMatch(name))
838 {
839
840 DC1constSETNP.setState(IPS_OK) ;
841 if (DC1constSETNP.getState() == IPS_OK)
842 DC1constSETNP.update(values, names, n);
843 DC1constSETNP.apply();
844 return true;
845 }
846 // DC2
847 if (DC2ControlNP.isNameMatch(name))
848 {
849 bool rc1 = false;
850 for (int i = 0; i < n; i++)
851 {
852 rc1 = setDewPWM(6, static_cast<uint8_t>(values[i]));
853 }
854
855 DC2ControlNP.setState( (rc1) ? IPS_OK : IPS_ALERT);
856 if (DC2ControlNP.getState() == IPS_OK)
857 DC2ControlNP.update(values, names, n);
858 DC2ControlNP.apply();
859 return true;
860 }
861 if (DC2diffSETNP.isNameMatch(name))
862 {
863
864 DC2diffSETNP.setState(IPS_OK) ;
865 if (DC2diffSETNP.getState() == IPS_OK)
866 DC2diffSETNP.update(values, names, n);
867 DC2diffSETNP.apply();
868 return true;
869 }
870 if (DC2constSETNP.isNameMatch(name))
871 {
872
873 DC2constSETNP.setState(IPS_OK) ;
874 if (DC2constSETNP.getState() == IPS_OK)
875 DC2constSETNP.update(values, names, n);
876 DC2constSETNP.apply();
877 return true;
878 }
879 // DC3
880 if (DC3ControlNP.isNameMatch(name))
881 {
882 bool rc1 = false;
883 for (int i = 0; i < n; i++)
884 {
885 rc1 = setDewPWM(7, static_cast<uint8_t>(values[i]));
886 }
887
888 DC3ControlNP.setState( (rc1) ? IPS_OK : IPS_ALERT);
889 if (DC3ControlNP.getState() == IPS_OK)
890 DC3ControlNP.update(values, names, n);
891 DC3ControlNP.apply();
892 return true;
893 }
894 if (DC3diffSETNP.isNameMatch(name))
895 {
896
897 DC3diffSETNP.setState(IPS_OK) ;
898 if (DC3diffSETNP.getState() == IPS_OK)
899 DC3diffSETNP.update(values, names, n);
900 DC3diffSETNP.apply();
901 return true;
902 }
903 if (DC3constSETNP.isNameMatch(name))
904 {
905
906 DC3constSETNP.setState(IPS_OK) ;
907 if (DC3constSETNP.getState() == IPS_OK)
908 DC3constSETNP.update(values, names, n);
909 DC3constSETNP.apply();
910 return true;
911 }
912
913
914 }
915 return INDI::DefaultDevice::ISNewNumber(dev, name, values, names, n);
916}
917
918bool WandererDewTerminator::setDewPWM(uint8_t id, uint8_t value)
919{
920 char cmd[64] = {0};
921 snprintf(cmd, 64, "%d%03d", id, value);
922 if (sendCommand(cmd))
923 {
924 return true;
925 }
926
927 return false;
928}
929
931{
932 return "Wanderer Dew Terminator";
933}
934
935
936bool WandererDewTerminator::sendCommand(std::string command)
937{
938 int nbytes_written = 0, rc = -1;
939 std::string command_termination = "\n";
940 LOGF_DEBUG("CMD: %s", command.c_str());
941 if ((rc = tty_write_string(PortFD, (command + command_termination).c_str(), &nbytes_written)) != TTY_OK)
942 {
943 char errorMessage[MAXRBUF];
944 tty_error_msg(rc, errorMessage, MAXRBUF);
945 LOGF_ERROR("Serial write error: %s", errorMessage);
946 return false;
947 }
948 return true;
949}
950
952{
953 if (!isConnected())
954 {
955 SetTimer(2500);
956 return;
957 }
958
959 getData();
960 SetTimer(2500);
961}
962
964{
966
967 DC1diffSP.save(fp);
968 DC1diffSETNP.save(fp);
969 DC1constSETNP.save(fp);
970 DC1ControlNP.save(fp);
971
972 DC2diffSP.save(fp);
973 DC2diffSETNP.save(fp);
974 DC2constSETNP.save(fp);
975 DC2ControlNP.save(fp);
976
977 DC3diffSP.save(fp);
978 DC3diffSETNP.save(fp);
979 DC3constSETNP.save(fp);
980 DC3ControlNP.save(fp);
981
982
983 return true;
984}
985
void log(const std::string &log)
Definition Utils.cpp:161
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)
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.
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
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
@ IPS_ALERT
Definition indiapi.h:162
@ IPS_IDLE
Definition indiapi.h:159
@ IPS_OK
Definition indiapi.h:160
@ ISR_1OFMANY
Definition indiapi.h:171
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
uint8_t cmd[4]
Definition pwc-ioctl.h:2