03f3865aeda4d29b7ce5a5173723e36fd62309f7
[public/netxms.git] / src / server / core / sensor.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2017 Raden Solutions
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: sensor.cpp
20 **/
21
22 #include "nxcore.h"
23
24 /**
25 * Default empty Sensor class constructior
26 */
27 Sensor::Sensor() : DataCollectionTarget()
28 {
29 m_proxyNodeId = 0;
30 m_flags = 0;
31 m_deviceClass = SENSOR_CLASS_UNKNOWN;
32 m_vendor = NULL;
33 m_commProtocol = SENSOR_PROTO_UNKNOWN;
34 m_xmlRegConfig = NULL;
35 m_xmlConfig = NULL;
36 m_serialNumber = NULL;
37 m_deviceAddress = NULL;
38 m_metaType = NULL;
39 m_description = NULL;
40 m_lastConnectionTime = 0;
41 m_frameCount = 0; //zero when no info
42 m_signalStrenght = 1; //+1 when no information(cannot be +)
43 m_signalNoise = MAX_INT32; //*10 from origin number
44 m_frequency = 0; //*10 from origin number
45 m_lastStatusPoll = 0;
46 m_lastConfigurationPoll = 0;
47 m_status = STATUS_UNKNOWN;
48 }
49
50 /**
51 * Constructor with all fields for Sensor class
52 */
53 Sensor::Sensor(TCHAR *name, UINT32 flags, MacAddress macAddress, UINT32 deviceClass, TCHAR *vendor,
54 UINT32 commProtocol, TCHAR *xmlRegConfig, TCHAR *xmlConfig, TCHAR *serialNumber, TCHAR *deviceAddress,
55 TCHAR *metaType, TCHAR *description, UINT32 proxyNode) : DataCollectionTarget(name)
56 {
57 m_flags = flags;
58 m_macAddress = macAddress;
59 m_deviceClass = deviceClass;
60 m_vendor = vendor;
61 m_commProtocol = commProtocol;
62 m_xmlRegConfig = xmlRegConfig;
63 m_xmlConfig = xmlConfig;
64 m_serialNumber = serialNumber;
65 m_deviceAddress = deviceAddress;
66 m_metaType = metaType;
67 m_description = description;
68 m_proxyNodeId = proxyNode;
69 m_lastConnectionTime = 0;
70 m_frameCount = 0; //zero when no info
71 m_signalStrenght = 1; //+1 when no information(cannot be +)
72 m_signalNoise = MAX_INT32; //*10 from origin number
73 m_frequency = 0; //*10 from origin number
74 m_lastStatusPoll = 0;
75 m_lastConfigurationPoll = 0;
76 m_status = STATUS_UNKNOWN;
77 }
78
79 Sensor *Sensor::createSensor(TCHAR *name, NXCPMessage *request)
80 {
81 Sensor *sensor = new Sensor(name,
82 request->getFieldAsUInt32(VID_SENSOR_FLAGS),
83 request->getFieldAsMacAddress(VID_MAC_ADDR),
84 request->getFieldAsUInt32(VID_DEVICE_CLASS),
85 request->getFieldAsString(VID_VENDOR),
86 request->getFieldAsUInt32(VID_COMM_PROTOCOL),
87 request->getFieldAsString(VID_XML_REG_CONFIG),
88 request->getFieldAsString(VID_XML_CONFIG),
89 request->getFieldAsString(VID_SERIAL_NUMBER),
90 request->getFieldAsString(VID_DEVICE_ADDRESS),
91 request->getFieldAsString(VID_META_TYPE),
92 request->getFieldAsString(VID_DESCRIPTION),
93 request->getFieldAsUInt32(VID_SENSOR_PROXY));
94
95 sensor->setNewNodeFlag();
96
97 switch(request->getFieldAsUInt32(VID_COMM_PROTOCOL))
98 {
99 case COMM_LORAWAN:
100 sensor->generateGuid();
101 if (registerLoraDevice(sensor) == NULL)
102 {
103 delete sensor;
104 return NULL;
105 }
106 break;
107 case COMM_DLMS:
108 sensor->m_state = SSF_PROVISIONED | SSF_REGISTERED | SSF_ACTIVE;
109 break;
110 }
111 return sensor;
112 }
113
114 /**
115 * Create agent connection
116 */
117 AgentConnectionEx *Sensor::getAgentConnection()
118 {
119 UINT32 rcc = ERR_CONNECT_FAILED;
120 if (IsShutdownInProgress())
121 return NULL;
122
123 NetObj *proxy = FindObjectById(m_proxyNodeId, OBJECT_NODE);
124 if(proxy == NULL)
125 return NULL;
126
127 return ((Node *)proxy)->acquireProxyConnection(SENSOR_PROXY);
128 }
129
130 /**
131 * Register LoRa WAN device
132 */
133 Sensor *Sensor::registerLoraDevice(Sensor *sensor)
134 {
135 NetObj *proxy = FindObjectById(sensor->m_proxyNodeId, OBJECT_NODE);
136 if(proxy == NULL)
137 return NULL;
138
139 AgentConnectionEx *conn = sensor->getAgentConnection();
140 if (conn == NULL)
141 {
142 return sensor; //Unprovisoned sensor - will try to provison it on next connect
143 }
144
145 Config regConfig;
146 Config config;
147 #ifdef UNICODE
148 char *regXml = UTF8StringFromWideString(sensor->getXmlRegConfig());
149 regConfig.loadXmlConfigFromMemory(regXml, (UINT32)strlen(regXml), NULL, "config", false);
150 free(regXml);
151
152 char *xml = UTF8StringFromWideString(sensor->getXmlConfig());
153 config.loadXmlConfigFromMemory(xml, (UINT32)strlen(xml), NULL, "config", false);
154 free(xml);
155 #else
156 regConfig.loadXmlConfigFromMemory(sensor->getXmlRegConfig(), (UINT32)strlen(sensor->getXmlRegConfig()), NULL, "config", false);
157 config.loadXmlConfigFromMemory(sensor->getXmlConfig(), (UINT32)strlen(sensor->getXmlConfig()), NULL, "config", false);
158 #endif
159
160
161
162 NXCPMessage msg(conn->getProtocolVersion());
163 msg.setCode(CMD_REGISTER_LORAWAN_SENSOR);
164 msg.setId(conn->generateRequestId());
165 msg.setField(VID_DEVICE_ADDRESS, sensor->getDeviceAddress());
166 msg.setField(VID_MAC_ADDR, sensor->getMacAddress());
167 msg.setField(VID_GUID, sensor->getGuid());
168 msg.setField(VID_DECODER, config.getValueAsInt(_T("/decoder"), 0));
169 msg.setField(VID_REG_TYPE, regConfig.getValueAsInt(_T("/registrationType"), 0));
170 if(regConfig.getValueAsInt(_T("/registrationType"), 0) == 0)
171 {
172 msg.setField(VID_LORA_APP_EUI, regConfig.getValue(_T("/appEUI")));
173 msg.setField(VID_LORA_APP_KEY, regConfig.getValue(_T("/appKey")));
174 }
175 else
176 {
177 msg.setField(VID_LORA_APP_S_KEY, regConfig.getValue(_T("/appSKey")));
178 msg.setField(VID_LORA_NWK_S_KWY, regConfig.getValue(_T("/nwkSKey")));
179 }
180 NXCPMessage *response = conn->customRequest(&msg);
181 if (response != NULL)
182 {
183 if(response->getFieldAsUInt32(VID_RCC) == RCC_SUCCESS)
184 {
185 sensor->lockProperties();
186 sensor->setProvisoned();
187 sensor->unlockProperties();
188 }
189 delete response;
190 }
191
192 return sensor;
193 }
194
195 //set correct status calculation function
196 //set correct configuration poll - provision if possible, for lora get device name, get all possible DCI's, try to do provisionning
197 //set status poll - check if connection is on if not generate alarm, check, that proxy is up and running
198
199 /**
200 * Sensor class destructor
201 */
202 Sensor::~Sensor()
203 {
204 free(m_vendor);
205 free(m_xmlRegConfig);
206 free(m_xmlConfig);
207 free(m_serialNumber);
208 free(m_deviceAddress);
209 free(m_metaType);
210 free(m_description);
211 }
212
213 /**
214 * Load from database SensorDevice class
215 */
216 bool Sensor::loadFromDatabase(DB_HANDLE hdb, UINT32 id)
217 {
218 m_id = id;
219
220 if (!loadCommonProperties(hdb))
221 {
222 nxlog_debug(2, _T("Cannot load common properties for sensor object %d"), id);
223 return false;
224 }
225
226 TCHAR query[512];
227 _sntprintf(query, 512, _T("SELECT mac_address,device_class,vendor,communication_protocol,xml_config,serial_number,device_address,")
228 _T("meta_type,description,last_connection_time,frame_count,signal_strenght,signal_noise,frequency,proxy_node,xml_reg_config FROM sensors WHERE id=%d"), m_id);
229 DB_RESULT hResult = DBSelect(hdb, query);
230 if (hResult == NULL)
231 return false;
232
233 m_macAddress = DBGetFieldMacAddr(hResult, 0, 0);
234 m_deviceClass = DBGetFieldULong(hResult, 0, 1);
235 m_vendor = DBGetField(hResult, 0, 2, NULL, 0);
236 m_commProtocol = DBGetFieldULong(hResult, 0, 3);
237 m_xmlConfig = DBGetField(hResult, 0, 4, NULL, 0);
238 m_serialNumber = DBGetField(hResult, 0, 5, NULL, 0);
239 m_deviceAddress = DBGetField(hResult, 0, 6, NULL, 0);
240 m_metaType = DBGetField(hResult, 0, 7, NULL, 0);
241 m_description = DBGetField(hResult, 0, 8, NULL, 0);
242 m_lastConnectionTime = DBGetFieldULong(hResult, 0, 9);
243 m_frameCount = DBGetFieldULong(hResult, 0, 10);
244 m_signalStrenght = DBGetFieldLong(hResult, 0, 11);
245 m_signalNoise = DBGetFieldLong(hResult, 0, 12);
246 m_frequency = DBGetFieldLong(hResult, 0, 13);
247 m_proxyNodeId = DBGetFieldLong(hResult, 0, 14);
248 m_xmlRegConfig = DBGetField(hResult, 0, 15, NULL, 0);
249 DBFreeResult(hResult);
250
251 // Load DCI and access list
252 loadACLFromDB(hdb);
253 loadItemsFromDB(hdb);
254 for(int i = 0; i < m_dcObjects->size(); i++)
255 if (!m_dcObjects->get(i)->loadThresholdsFromDB(hdb))
256 return false;
257
258 return true;
259 }
260
261 /**
262 * Save to database Sensor class
263 */
264 bool Sensor::saveToDatabase(DB_HANDLE hdb)
265 {
266 lockProperties();
267
268 bool success = saveCommonProperties(hdb);
269
270 if (success && (m_modified & MODIFY_SENSOR_PROPERTIES))
271 {
272 DB_STATEMENT hStmt;
273 bool isNew = !(IsDatabaseRecordExist(hdb, _T("sensors"), _T("id"), m_id));
274 if (isNew)
275 hStmt = DBPrepare(hdb, _T("INSERT INTO sensors (mac_address,device_class,vendor,communication_protocol,xml_config,serial_number,device_address,meta_type,description,last_connection_time,frame_count,signal_strenght,signal_noise,frequency,proxy_node,id,xml_reg_config) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
276 else
277 hStmt = DBPrepare(hdb, _T("UPDATE sensors SET mac_address=?,device_class=?,vendor=?,communication_protocol=?,xml_config=?,serial_number=?,device_address=?,meta_type=?,description=?,last_connection_time=?,frame_count=?,signal_strenght=?,signal_noise=?,frequency=?,proxy_node=? WHERE id=?"));
278 if (hStmt != NULL)
279 {
280 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, m_macAddress);
281 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, (INT32)m_deviceClass);
282 DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, m_vendor, DB_BIND_STATIC);
283 DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, (INT32)m_commProtocol);
284 DBBind(hStmt, 5, DB_SQLTYPE_VARCHAR, m_xmlConfig, DB_BIND_STATIC);
285 DBBind(hStmt, 6, DB_SQLTYPE_VARCHAR, m_serialNumber, DB_BIND_STATIC);
286 DBBind(hStmt, 7, DB_SQLTYPE_VARCHAR, m_deviceAddress, DB_BIND_STATIC);
287 DBBind(hStmt, 8, DB_SQLTYPE_VARCHAR, m_metaType, DB_BIND_STATIC);
288 DBBind(hStmt, 9, DB_SQLTYPE_VARCHAR, m_description, DB_BIND_STATIC);
289 DBBind(hStmt, 10, DB_SQLTYPE_INTEGER, (UINT32)m_lastConnectionTime);
290 DBBind(hStmt, 11, DB_SQLTYPE_INTEGER, m_frameCount);
291 DBBind(hStmt, 12, DB_SQLTYPE_INTEGER, m_signalStrenght);
292 DBBind(hStmt, 13, DB_SQLTYPE_INTEGER, m_signalNoise);
293 DBBind(hStmt, 14, DB_SQLTYPE_INTEGER, m_frequency);
294 DBBind(hStmt, 15, DB_SQLTYPE_INTEGER, m_proxyNodeId);
295 DBBind(hStmt, 16, DB_SQLTYPE_INTEGER, m_id);
296 if (isNew)
297 DBBind(hStmt, 17, DB_SQLTYPE_VARCHAR, m_xmlRegConfig, DB_BIND_STATIC);
298
299 success = DBExecute(hStmt);
300
301 DBFreeStatement(hStmt);
302 }
303 else
304 {
305 success = false;
306 }
307 }
308
309 // Save data collection items
310 if (success && (m_modified & MODIFY_DATA_COLLECTION))
311 {
312 lockDciAccess(false);
313 for(int i = 0; i < m_dcObjects->size(); i++)
314 m_dcObjects->get(i)->saveToDatabase(hdb);
315 unlockDciAccess();
316 }
317
318 // Save access list
319 if (success)
320 saveACLToDB(hdb);
321
322 // Clear modifications flag and unlock object
323 if (success)
324 m_modified = 0;
325 unlockProperties();
326
327 return success;
328 }
329
330 /**
331 * Delete from database
332 */
333 bool Sensor::deleteFromDatabase(DB_HANDLE hdb)
334 {
335 bool success = DataCollectionTarget::deleteFromDatabase(hdb);
336 if (success)
337 success = executeQueryOnObject(hdb, _T("DELETE FROM sensors WHERE id=?"));
338 return success;
339 }
340
341 /**
342 * Create NXSL object for this object
343 */
344 NXSL_Value *Sensor::createNXSLObject()
345 {
346 return new NXSL_Value(new NXSL_Object(&g_nxslSensorClass, this));
347 }
348
349 /**
350 * Sensor class serialization to json
351 */
352 json_t *Sensor::toJson()
353 {
354 json_t *root = DataCollectionTarget::toJson();
355 json_object_set_new(root, "flags", json_integer(m_flags));
356 json_object_set_new(root, "macAddr", json_string_t(m_macAddress.toString(MAC_ADDR_FLAT_STRING)));
357 json_object_set_new(root, "deviceClass", json_integer(m_deviceClass));
358 json_object_set_new(root, "vendor", json_string_t(m_vendor));
359 json_object_set_new(root, "commProtocol", json_integer(m_commProtocol));
360 json_object_set_new(root, "xmlConfig", json_string_t(m_xmlConfig));
361 json_object_set_new(root, "serialNumber", json_string_t(m_serialNumber));
362 json_object_set_new(root, "deviceAddress", json_string_t(m_deviceAddress));
363 json_object_set_new(root, "metaType", json_string_t(m_metaType));
364 json_object_set_new(root, "description", json_string_t(m_description));
365 json_object_set_new(root, "proxyNode", json_integer(m_proxyNodeId));
366 return root;
367 }
368
369 void Sensor::fillMessageInternal(NXCPMessage *msg)
370 {
371 DataCollectionTarget::fillMessageInternal(msg);
372 msg->setField(VID_SENSOR_FLAGS, m_flags);
373 msg->setField(VID_MAC_ADDR, m_macAddress);
374 msg->setField(VID_DEVICE_CLASS, m_deviceClass);
375 msg->setField(VID_VENDOR, CHECK_NULL_EX(m_vendor));
376 msg->setField(VID_COMM_PROTOCOL, m_commProtocol);
377 msg->setField(VID_XML_CONFIG, CHECK_NULL_EX(m_xmlConfig));
378 msg->setField(VID_XML_REG_CONFIG, CHECK_NULL_EX(m_xmlRegConfig));
379 msg->setField(VID_SERIAL_NUMBER, CHECK_NULL_EX(m_serialNumber));
380 msg->setField(VID_DEVICE_ADDRESS, CHECK_NULL_EX(m_deviceAddress));
381 msg->setField(VID_META_TYPE, CHECK_NULL_EX(m_metaType));
382 msg->setField(VID_DESCRIPTION, CHECK_NULL_EX(m_description));
383 msg->setFieldFromTime(VID_LAST_CONN_TIME, m_lastConnectionTime);
384 msg->setField(VID_FRAME_COUNT, m_frameCount);
385 msg->setField(VID_SIGNAL_STRENGHT, m_signalStrenght);
386 msg->setField(VID_SIGNAL_NOISE, m_signalNoise);
387 msg->setField(VID_FREQUENCY, m_frequency);
388 msg->setField(VID_SENSOR_PROXY, m_proxyNodeId);
389 }
390
391 UINT32 Sensor::modifyFromMessageInternal(NXCPMessage *request)
392 {
393 if (request->isFieldExist(VID_FLAGS))
394 m_flags = request->getFieldAsUInt32(VID_FLAGS);
395
396 if (request->isFieldExist(VID_MAC_ADDR))
397 m_macAddress = request->getFieldAsMacAddress(VID_MAC_ADDR);
398 if (request->isFieldExist(VID_VENDOR))
399 {
400 free(m_vendor);
401 m_vendor = request->getFieldAsString(VID_VENDOR);
402 }
403 if (request->isFieldExist(VID_DEVICE_CLASS))
404 m_deviceClass = request->getFieldAsUInt32(VID_DEVICE_CLASS);
405 if (request->isFieldExist(VID_SERIAL_NUMBER))
406 {
407 free(m_serialNumber);
408 m_serialNumber = request->getFieldAsString(VID_SERIAL_NUMBER);
409 }
410 if (request->isFieldExist(VID_DEVICE_ADDRESS))
411 {
412 free(m_deviceAddress);
413 m_deviceAddress = request->getFieldAsString(VID_DEVICE_ADDRESS);
414 }
415 if (request->isFieldExist(VID_META_TYPE))
416 {
417 free(m_metaType);
418 m_metaType = request->getFieldAsString(VID_META_TYPE);
419 }
420 if (request->isFieldExist(VID_DESCRIPTION))
421 {
422 free(m_description);
423 m_description = request->getFieldAsString(VID_DESCRIPTION);
424 }
425 if (request->isFieldExist(VID_SENSOR_PROXY))
426 m_proxyNodeId = request->getFieldAsUInt32(VID_SENSOR_PROXY);
427 if (request->isFieldExist(VID_XML_CONFIG))
428 {
429 free(m_xmlConfig);
430 m_xmlConfig = request->getFieldAsString(VID_XML_CONFIG);
431 }
432
433 return DataCollectionTarget::modifyFromMessageInternal(request);
434 }
435
436 /**
437 * Calculate sensor status
438 */
439 void Sensor::calculateCompoundStatus(BOOL bForcedRecalc)
440 {
441 UINT32 oldStatus = m_status;
442 calculateStatus(bForcedRecalc);
443 lockProperties();
444 if (oldStatus != m_status)
445 setModified(MODIFY_RUNTIME);
446 unlockProperties();
447 }
448
449 void Sensor::calculateStatus(BOOL bForcedRecalc)
450 {
451 AgentConnectionEx *conn = getAgentConnection();
452 if (conn == NULL)
453 {
454 m_status = STATUS_UNKNOWN;
455 return;
456 }
457 DataCollectionTarget::calculateCompoundStatus(bForcedRecalc);
458 lockProperties();
459 int status = 0;
460 if (m_state == 0 || m_state == SSF_PROVISIONED)
461 status = STATUS_UNKNOWN;
462 else if (m_state & SSF_ACTIVE)
463 status = STATUS_NORMAL;
464 else
465 status = STATUS_CRITICAL;
466
467 m_status = m_status != STATUS_UNKNOWN ? std::max(m_status, status) : status;
468 unlockProperties();
469 }
470
471 /**
472 * Get instances for instance discovery DCO
473 */
474 StringMap *Sensor::getInstanceList(DCObject *dco)
475 {
476 if (dco->getInstanceDiscoveryData() == NULL)
477 return NULL;
478
479 DataCollectionTarget *obj;
480 if (dco->getSourceNode() != 0)
481 {
482 obj = (DataCollectionTarget *)FindObjectById(dco->getSourceNode(), OBJECT_NODE);
483 if (obj == NULL)
484 {
485 DbgPrintf(6, _T("Sensor::getInstanceList(%s [%d]): source node [%d] not found"), dco->getName(), dco->getId(), dco->getSourceNode());
486 return NULL;
487 }
488 if (!obj->isTrustedNode(m_id))
489 {
490 DbgPrintf(6, _T("Sensor::getInstanceList(%s [%d]): this node (%s [%d]) is not trusted by source sensor %s [%d]"),
491 dco->getName(), dco->getId(), m_name, m_id, obj->getName(), obj->getId());
492 return NULL;
493 }
494 }
495 else
496 {
497 obj = this;
498 }
499
500 StringList *instances = NULL;
501 StringMap *instanceMap = NULL;
502 switch(dco->getInstanceDiscoveryMethod())
503 {
504 case IDM_AGENT_LIST:
505 if (obj->getObjectClass() == OBJECT_NODE)
506 ((Node *)obj)->getListFromAgent(dco->getInstanceDiscoveryData(), &instances);
507 else if (obj->getObjectClass() == OBJECT_SENSOR)
508 ((Sensor *)obj)->getListFromAgent(dco->getInstanceDiscoveryData(), &instances);
509 break;
510 case IDM_SCRIPT:
511 obj->getStringMapFromScript(dco->getInstanceDiscoveryData(), &instanceMap, this);
512 break;
513 default:
514 instances = NULL;
515 break;
516 }
517 if ((instances == NULL) && (instanceMap == NULL))
518 return NULL;
519
520 if (instanceMap == NULL)
521 {
522 instanceMap = new StringMap;
523 for(int i = 0; i < instances->size(); i++)
524 instanceMap->set(instances->get(i), instances->get(i));
525 }
526 delete instances;
527 return instanceMap;
528 }
529
530 /**
531 * Perform configuration poll on node
532 */
533 void Sensor::configurationPoll(PollerInfo *poller, ClientSession *session, UINT32 rqId)
534 {
535 if (m_runtimeFlags & DCDF_DELETE_IN_PROGRESS)
536 {
537 if (rqId == 0)
538 m_runtimeFlags &= ~DCDF_QUEUED_FOR_CONFIGURATION_POLL;
539 return;
540 }
541
542 poller->setStatus(_T("wait for lock"));
543 pollerLock();
544
545 if (IsShutdownInProgress())
546 {
547 pollerUnlock();
548 return;
549 }
550
551 m_pollRequestor = session;
552 nxlog_debug(5, _T("Starting configuration poll for sensor %s (ID: %d), m_flags: %d"), m_name, m_id, m_flags);
553
554 bool hasChanges = false;
555
556 if (m_commProtocol == COMM_LORAWAN)
557 {
558 if (!(m_state & SSF_PROVISIONED))
559 {
560 if ((registerLoraDevice(this) != NULL) && (m_state & SSF_PROVISIONED))
561 {
562 nxlog_debug(6, _T("ConfPoll(%s [%d}): sensor successfully registered"), m_name, m_id);
563 hasChanges = true;
564 }
565 }
566 if ((m_state & SSF_PROVISIONED) && (m_deviceAddress == NULL))
567 {
568 getItemFromAgent(_T("LoraWAN.DevAddr(*)"), 0, m_deviceAddress);
569 if (m_deviceAddress != NULL)
570 {
571 nxlog_debug(6, _T("ConfPoll(%s [%d}): sensor DevAddr[%s] successfully obtained"), m_name, m_id, m_deviceAddress);
572 hasChanges = true;
573 }
574 }
575 }
576
577 applyUserTemplates();
578 updateContainerMembership();
579
580 // Execute hook script
581 poller->setStatus(_T("hook"));
582 executeHookScript(_T("ConfigurationPoll"));
583
584 sendPollerMsg(rqId, _T("Finished configuration poll for sensor %s\r\n"), m_name);
585 sendPollerMsg(rqId, _T("Sensor configuration was%schanged after poll\r\n"), hasChanges ? _T(" ") : _T(" not "));
586
587 if (rqId == 0)
588 m_runtimeFlags &= ~DCDF_QUEUED_FOR_CONFIGURATION_POLL;
589 m_lastConfigurationPoll = time(NULL);
590
591 nxlog_debug(5, _T("Finished configuration poll for sensor %s (ID: %d)"), m_name, m_id);
592 m_runtimeFlags &= ~DCDF_POLL_NEW_NODE;
593 m_runtimeFlags |= DCDF_CONFIGURATION_POLL_PASSED;
594 pollerUnlock();
595
596 if (hasChanges)
597 {
598 lockProperties();
599 setModified(MODIFY_SENSOR_PROPERTIES);
600 unlockProperties();
601 }
602
603 }
604
605 /**
606 * Check if DLMS converter used for sensor access is accessible
607 */
608 void Sensor::checkDlmsConverterAccessibility()
609 {
610 //Create conectivity test DCI and try to get it's result
611 }
612
613 /**
614 * Perform status poll on sensor
615 */
616 void Sensor::statusPoll(PollerInfo *poller, ClientSession *session, UINT32 rqId)
617 {
618 if (m_runtimeFlags & DCDF_DELETE_IN_PROGRESS)
619 {
620 if (rqId == 0)
621 m_runtimeFlags &= ~DCDF_QUEUED_FOR_STATUS_POLL;
622 return;
623 }
624
625 Queue *pQueue = new Queue; // Delayed event queue
626
627 poller->setStatus(_T("wait for lock"));
628 pollerLock();
629
630 if (IsShutdownInProgress())
631 {
632 delete pQueue;
633 pollerUnlock();
634 return;
635 }
636
637 m_pollRequestor = session;
638 sendPollerMsg(rqId, _T("Starting status poll for sensor %s\r\n"), m_name);
639 nxlog_debug(5, _T("Starting status poll for sensor %s (ID: %d)"), m_name, m_id);
640
641 UINT32 prevState = m_state;
642
643 nxlog_debug(6, _T("StatusPoll(%s): checking agent"), m_name);
644 poller->setStatus(_T("check agent"));
645 sendPollerMsg(rqId, _T("Checking NetXMS agent connectivity\r\n"));
646
647 AgentConnectionEx *conn = getAgentConnection();
648 lockProperties();
649 if (conn != NULL)
650 {
651 nxlog_debug(6, _T("StatusPoll(%s): connected to agent"), m_name);
652 if (m_state & DCSF_UNREACHABLE)
653 {
654 m_state &= ~DCSF_UNREACHABLE;
655 sendPollerMsg(rqId, POLLER_INFO _T("Connectivity with NetXMS agent restored\r\n"));
656 }
657 }
658 else
659 {
660 nxlog_debug(6, _T("StatusPoll(%s): agent unreachable"), m_name);
661 sendPollerMsg(rqId, POLLER_ERROR _T("NetXMS agent unreachable\r\n"));
662 if (!(m_state & DCSF_UNREACHABLE))
663 m_state |= DCSF_UNREACHABLE;
664 }
665 unlockProperties();
666 nxlog_debug(6, _T("StatusPoll(%s): agent check finished"), m_name);
667
668 switch(m_commProtocol)
669 {
670 case COMM_LORAWAN:
671 if (m_runtimeFlags & SSF_PROVISIONED)
672 {
673 lockProperties();
674 TCHAR lastValue[MAX_DCI_STRING_VALUE] = { 0 };
675 time_t now;
676 getItemFromAgent(_T("LoraWAN.LastContact(*)"), MAX_DCI_STRING_VALUE, lastValue);
677 time_t lastConnectionTime = _tcstol(lastValue, NULL, 0);
678 if (lastConnectionTime != 0)
679 {
680 m_lastConnectionTime = lastConnectionTime;
681 nxlog_debug(6, _T("StatusPoll(%s [%d}): Last connection time updated - %d"), m_name, m_id, m_lastConnectionTime);
682 }
683
684 now = time(NULL);
685
686 if (!(m_state & SSF_REGISTERED))
687 {
688 if (m_lastConnectionTime > 0)
689 {
690 m_state |= SSF_REGISTERED;
691 nxlog_debug(6, _T("StatusPoll(%s [%d}): Status set to REGISTERED"), m_name, m_id);
692 }
693 }
694 if (m_state & SSF_REGISTERED)
695 {
696 if (now - m_lastConnectionTime > 3600) // Last contact > 1h
697 {
698 m_state &= ~SSF_ACTIVE;
699 nxlog_debug(6, _T("StatusPoll(%s [%d}): Inactive for over 1h, status set to INACTIVE"), m_name, m_id);
700 }
701 else
702 {
703 // FIXME: modify runtime if needed
704 m_state |= SSF_ACTIVE;
705 nxlog_debug(6, _T("StatusPoll(%s [%d]): Status set to ACTIVE"), m_name, m_id);
706 getItemFromAgent(_T("LoraWAN.RSSI(*)"), MAX_DCI_STRING_VALUE, lastValue);
707 m_signalStrenght = _tcstol(lastValue, NULL, 10);
708 getItemFromAgent(_T("LoraWAN.SNR(*)"), MAX_DCI_STRING_VALUE, lastValue);
709 m_signalNoise = static_cast<INT32>(_tcstod(lastValue, NULL) * 10);
710 getItemFromAgent(_T("LoraWAN.Frequency(*)"), MAX_DCI_STRING_VALUE, lastValue);
711 m_frequency = static_cast<UINT32>(_tcstod(lastValue, NULL) * 10);
712 }
713 }
714
715 unlockProperties();
716 }
717 break;
718 case COMM_DLMS:
719 checkDlmsConverterAccessibility();
720 break;
721 default:
722 break;
723 }
724 calculateStatus(TRUE);
725
726 // Send delayed events and destroy delayed event queue
727 if (pQueue != NULL)
728 {
729 ResendEvents(pQueue);
730 delete pQueue;
731 }
732 poller->setStatus(_T("hook"));
733 executeHookScript(_T("StatusPoll"));
734
735 if (rqId == 0)
736 m_runtimeFlags &= ~DCDF_QUEUED_FOR_STATUS_POLL;
737
738 if (prevState != m_state)
739 setModified(MODIFY_SENSOR_PROPERTIES);
740
741 sendPollerMsg(rqId, _T("Finished status poll for sensor %s\r\n"), m_name);
742 sendPollerMsg(rqId, _T("Sensor status after poll is %s\r\n"), GetStatusAsText(m_status, true));
743
744 pollerUnlock();
745 m_lastStatusPoll = time(NULL);
746 nxlog_debug(5, _T("Finished status poll for sensor %s (ID: %d)"), m_name, m_id);
747 }
748
749 void Sensor::prepareLoraDciParameters(String &parameter)
750 {
751 int place = parameter.find(_T(")"));
752 if(place > 0)
753 {
754 parameter.replace(_T(")"), m_guid.toString());
755 parameter.append(_T(")"));
756 }
757 else
758 {
759 parameter.append(_T("("));
760 parameter.append(m_guid.toString());
761 parameter.append(_T(")"));
762 }
763 }
764
765 /**
766 * Set all required parameters for DLMS request
767 */
768 void Sensor::prepareDlmsDciParameters(String &parameter)
769 {
770 Config config;
771 #ifdef UNICODE
772 char *xml = UTF8StringFromWideString(m_xmlConfig);
773 config.loadXmlConfigFromMemory(xml, (UINT32)strlen(xml), NULL, "config", false);
774 free(xml);
775 #else
776 config.loadXmlConfigFromMemory(m_xmlConfig, (UINT32)strlen(m_xmlConfig), NULL, "config", false);
777 #endif
778 ConfigEntry *configRoot = config.getEntry(_T("/connections"));
779 if (configRoot != NULL)
780 {
781 int place = parameter.find(_T(")"));
782 if(place > 0)
783 {
784 parameter.replace(_T(")"), _T(""));
785 }
786 else
787 {
788 parameter.append(_T("("));
789 }
790 ObjectArray<ConfigEntry> *credentials = configRoot->getSubEntries(_T("/cred"));
791 for(int i = 0; i < credentials->size(); i++)
792 {
793 ConfigEntry *cred = credentials->get(i);
794 parameter.append(_T(","));
795 parameter.append(cred->getSubEntryValueAsInt(_T("/lineType")));
796 parameter.append(_T(","));
797 parameter.append(cred->getSubEntryValueAsInt(_T("/port")));
798 parameter.append(_T(","));
799 parameter.append(cred->getSubEntryValueAsInt(_T("/password")));
800 parameter.append(_T(","));
801 parameter.append(cred->getSubEntryValue(_T("/inetAddress")));
802 parameter.append(_T(","));
803 parameter.append(cred->getSubEntryValueAsInt(_T("/linkNumber")));
804 parameter.append(_T(","));
805 parameter.append(cred->getSubEntryValueAsInt(_T("/lineNumber")));
806 parameter.append(_T(","));
807 parameter.append(cred->getSubEntryValueAsInt(_T("/linkParams")));
808 }
809 parameter.append(_T(")"));
810 delete credentials;
811 }
812
813 /*
814 config.
815 //set number of configurations
816 //set all parameters
817 <config>
818 <connections class="java.util.ArrayList">
819 <cred>
820 <lineType>32</lineType>
821 <port>3001</port>
822 <password>ABCD</password>
823 <inetAddress>127.0.0.1</inetAddress>
824 <linkNumber>54</linkNumber>
825 <lineNumber>31</lineNumber>
826 <linkParams>1231</linkParams>
827 </cred>
828 </connections>
829 </config>
830 */
831 }
832
833 /**
834 * Get item's value via native agent
835 */
836 UINT32 Sensor::getItemFromAgent(const TCHAR *szParam, UINT32 dwBufSize, TCHAR *szBuffer)
837 {
838 if (m_state & DCSF_UNREACHABLE)
839 return DCE_COMM_ERROR;
840
841 UINT32 dwError = ERR_NOT_CONNECTED, dwResult = DCE_COMM_ERROR;
842 int retry = 3;
843
844 nxlog_debug(7, _T("Sensor(%s)->GetItemFromAgent(%s)"), m_name, szParam);
845 // Establish connection if needed
846 AgentConnectionEx *conn = getAgentConnection();
847 if (conn == NULL)
848 {
849 return dwResult;
850 }
851
852 String parameter(szParam);
853 switch(m_commProtocol)
854 {
855 case COMM_LORAWAN:
856 prepareLoraDciParameters(parameter);
857 break;
858 case COMM_DLMS:
859 if(parameter.find(_T("Sensor")) != -1)
860 prepareDlmsDciParameters(parameter);
861 break;
862 }
863 nxlog_debug(3, _T("Sensor(%s)->GetItemFromAgent(%s)"), m_name, parameter.getBuffer());
864
865 // Get parameter from agent
866 while(retry-- > 0)
867 {
868 dwError = conn->getParameter(parameter, dwBufSize, szBuffer);
869 switch(dwError)
870 {
871 case ERR_SUCCESS:
872 dwResult = DCE_SUCCESS;
873 break;
874 case ERR_UNKNOWN_PARAMETER:
875 dwResult = DCE_NOT_SUPPORTED;
876 break;
877 case ERR_NO_SUCH_INSTANCE:
878 dwResult = DCE_NO_SUCH_INSTANCE;
879 break;
880 case ERR_NOT_CONNECTED:
881 case ERR_CONNECTION_BROKEN:
882 break;
883 case ERR_REQUEST_TIMEOUT:
884 // Reset connection to agent after timeout
885 nxlog_debug(7, _T("Sensor(%s)->GetItemFromAgent(%s): timeout; resetting connection to agent..."), m_name, szParam);
886 if (getAgentConnection() == NULL)
887 break;
888 nxlog_debug(7, _T("Sensor(%s)->GetItemFromAgent(%s): connection to agent restored successfully"), m_name, szParam);
889 break;
890 case ERR_INTERNAL_ERROR:
891 dwResult = DCE_COLLECTION_ERROR;
892 break;
893 }
894 }
895
896 nxlog_debug(7, _T("Sensor(%s)->GetItemFromAgent(%s): dwError=%d dwResult=%d"), m_name, szParam, dwError, dwResult);
897 return dwResult;
898 }
899
900 /**
901 * Get list from agent
902 */
903 UINT32 Sensor::getListFromAgent(const TCHAR *name, StringList **list)
904 {
905 UINT32 dwError = ERR_NOT_CONNECTED, dwResult = DCE_COMM_ERROR;
906 UINT32 i, dwTries = 3;
907
908 *list = NULL;
909
910 if (m_state & DCSF_UNREACHABLE) //removed disable agent usage for all polls
911 return DCE_COMM_ERROR;
912
913 nxlog_debug(7, _T("Sensor(%s)->GetItemFromAgent(%s)"), m_name, name);
914 AgentConnectionEx *conn = getAgentConnection();
915 if (conn == NULL)
916 {
917 return dwResult;
918 }
919
920 String parameter(name);
921 switch(m_commProtocol)
922 {
923 case COMM_LORAWAN:
924 prepareLoraDciParameters(parameter);
925 break;
926 case COMM_DLMS:
927 if(parameter.find(_T("Sensor")) != -1)
928 prepareDlmsDciParameters(parameter);
929 break;
930 }
931 nxlog_debug(3, _T("Sensor(%s)->GetItemFromAgent(%s)"), m_name, parameter.getBuffer());
932
933 // Get parameter from agent
934 while(dwTries-- > 0)
935 {
936 dwError = conn->getList(parameter);
937 switch(dwError)
938 {
939 case ERR_SUCCESS:
940 dwResult = DCE_SUCCESS;
941 *list = new StringList;
942 for(i = 0; i < conn->getNumDataLines(); i++)
943 (*list)->add(conn->getDataLine(i));
944 break;
945 case ERR_UNKNOWN_PARAMETER:
946 dwResult = DCE_NOT_SUPPORTED;
947 break;
948 case ERR_NO_SUCH_INSTANCE:
949 dwResult = DCE_NO_SUCH_INSTANCE;
950 break;
951 case ERR_NOT_CONNECTED:
952 case ERR_CONNECTION_BROKEN:
953 case ERR_REQUEST_TIMEOUT:
954 // Reset connection to agent after timeout
955 DbgPrintf(7, _T("Sensor(%s)->getListFromAgent(%s): timeout; resetting connection to agent..."), m_name, name);
956 if (getAgentConnection() == NULL)
957 break;
958 break;
959 DbgPrintf(7, _T("Sensor(%s)->getListFromAgent(%s): connection to agent restored successfully"), m_name, name);
960 break;
961 case ERR_INTERNAL_ERROR:
962 dwResult = DCE_COLLECTION_ERROR;
963 break;
964 }
965 }
966
967 DbgPrintf(7, _T("Sensor(%s)->getListFromAgent(%s): dwError=%d dwResult=%d"), m_name, name, dwError, dwResult);
968 return dwResult;
969 }
970
971 /**
972 * Prepare sensor object for deletion
973 */
974 void Sensor::prepareForDeletion()
975 {
976 // Prevent sensor from being queued for polling
977 lockProperties();
978 m_runtimeFlags |= DCDF_DELETE_IN_PROGRESS;
979 unlockProperties();
980
981 // Wait for all pending polls
982 nxlog_debug(4, _T("Sensor::PrepareForDeletion(%s [%d]): waiting for outstanding polls to finish"), m_name, m_id);
983 while(1)
984 {
985 lockProperties();
986 if ((m_runtimeFlags &
987 (DCDF_QUEUED_FOR_STATUS_POLL | DCDF_QUEUED_FOR_CONFIGURATION_POLL)) == 0)
988 {
989 unlockProperties();
990 break;
991 }
992 unlockProperties();
993 ThreadSleepMs(100);
994 }
995 nxlog_debug(4, _T("Sensor::PrepareForDeletion(%s [%d]): no outstanding polls left"), m_name, m_id);
996
997 AgentConnectionEx *conn = getAgentConnection();
998 if(m_commProtocol == COMM_LORAWAN && conn != NULL)
999 {
1000 NXCPMessage msg(conn->getProtocolVersion());
1001 msg.setCode(CMD_UNREGISTER_LORAWAN_SENSOR);
1002 msg.setId(conn->generateRequestId());
1003 msg.setField(VID_GUID, m_guid);
1004 NXCPMessage *response = conn->customRequest(&msg);
1005 if (response != NULL)
1006 {
1007 if(response->getFieldAsUInt32(VID_RCC) == RCC_SUCCESS)
1008 nxlog_debug(4, _T("Sensor::PrepareForDeletion(%s [%d]): successfully unregistered from LoRaWAN server"), m_name, m_id);
1009
1010 delete response;
1011 }
1012 }
1013
1014 DataCollectionTarget::prepareForDeletion();
1015 }