diff --git a/CMakeLists.txt b/CMakeLists.txt index d633dfaa..c08fe7d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,6 +124,18 @@ set(SOURCE_FILES pulsecounter/Factory.h pulsecounter/MyNode.cpp pulsecounter/MyNode.h + serial/serial-port/Factory.cpp + serial/serial-port/Factory.h + serial/serial-port/MyNode.cpp + serial/serial-port/MyNode.h + serial/serial-in/Factory.cpp + serial/serial-in/Factory.h + serial/serial-in/MyNode.cpp + serial/serial-in/MyNode.h + serial/serial-out/Factory.cpp + serial/serial-out/Factory.h + serial/serial-out/MyNode.cpp + serial/serial-out/MyNode.h storage/file/Factory.cpp storage/file/Factory.h storage/file/MyNode.cpp diff --git a/Makefile.am b/Makefile.am index 87624489..3b782739 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,3 +1,3 @@ AUTOMAKE_OPTIONS = foreign ACLOCAL_AMFLAGS = -I m4 -I cfg -SUBDIRS = average basic-logic comment debug function gpio http influxdb light link modbus mqtt notification parsers passthrough ping pulsecounter press-pattern synchronous storage template timers tls-config tls-server-config variable +SUBDIRS = average basic-logic comment debug function gpio http influxdb light link modbus mqtt notification parsers passthrough ping pulsecounter press-pattern serial synchronous storage template timers tls-config tls-server-config variable diff --git a/configure.ac b/configure.ac index 79331432..4df7c5a2 100644 --- a/configure.ac +++ b/configure.ac @@ -62,4 +62,4 @@ esac #AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug], [enable debugging, default: no]), [case "${enableval}" in yes) debug=true ;; no) debug=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-debug]) ;; esac], [debug=false]) #AM_CONDITIONAL(DEBUG, test x"$debug" = x"true") -AC_OUTPUT(Makefile average/Makefile basic-logic/Makefile comment/Makefile debug/Makefile function/Makefile gpio/Makefile http/Makefile influxdb/Makefile light/Makefile link/Makefile modbus/Makefile mqtt/Makefile notification/Makefile parsers/Makefile passthrough/Makefile ping/Makefile press-pattern/Makefile pulsecounter/Makefile synchronous/Makefile storage/Makefile template/Makefile timers/Makefile tls-config/Makefile tls-server-config/Makefile variable/Makefile) +AC_OUTPUT(Makefile average/Makefile basic-logic/Makefile comment/Makefile debug/Makefile function/Makefile gpio/Makefile http/Makefile influxdb/Makefile light/Makefile link/Makefile modbus/Makefile mqtt/Makefile notification/Makefile parsers/Makefile passthrough/Makefile ping/Makefile press-pattern/Makefile pulsecounter/Makefile serial/Makefile synchronous/Makefile storage/Makefile template/Makefile timers/Makefile tls-config/Makefile tls-server-config/Makefile variable/Makefile) diff --git a/modbus/modbus-host/MyNode.cpp b/modbus/modbus-host/MyNode.cpp index 6d0517bd..99d4b6fa 100644 --- a/modbus/modbus-host/MyNode.cpp +++ b/modbus/modbus-host/MyNode.cpp @@ -334,7 +334,7 @@ Flows::PVariable MyNode::writeRegisters(Flows::PArray parameters) { try { - if(parameters->size() != 4 && parameters->size() != 6) return Flows::Variable::createError(-1, "Method expects four or sic parameters. " + std::to_string(parameters->size()) + " given."); + if(parameters->size() != 4 && parameters->size() != 6) return Flows::Variable::createError(-1, "Method expects four or six parameters. " + std::to_string(parameters->size()) + " given."); if (!_modbus) return Flows::Variable::createError(-32500, "Unknown application error."); if((Modbus::ModbusType)parameters->at(0)->integerValue == Modbus::ModbusType::tHoldingRegister && parameters->size() == 6) diff --git a/mqtt/mqtt-broker/MyNode.cpp b/mqtt/mqtt-broker/MyNode.cpp index 675d855e..fdcda464 100644 --- a/mqtt/mqtt-broker/MyNode.cpp +++ b/mqtt/mqtt-broker/MyNode.cpp @@ -201,7 +201,7 @@ Flows::PVariable MyNode::registerNode(Flows::PArray parameters) try { if(parameters->size() != 1) return Flows::Variable::createError(-1, "Method expects exactly one parameter. " + std::to_string(parameters->size()) + " given."); - if(parameters->at(0)->type != Flows::VariableType::tString) return Flows::Variable::createError(-1, "Parameter is not of type string."); + if(parameters->at(0)->type != Flows::VariableType::tString || parameters->at(0)->stringValue.empty()) return Flows::Variable::createError(-1, "Parameter is not of type string."); if(_mqtt) _mqtt->registerNode(parameters->at(0)->stringValue); diff --git a/serial/Makefile.am b/serial/Makefile.am new file mode 100644 index 00000000..5667845d --- /dev/null +++ b/serial/Makefile.am @@ -0,0 +1,28 @@ +AUTOMAKE_OPTIONS = subdir-objects + +AM_CPPFLAGS = -Wall -std=c++11 -DFORTIFY_SOURCE=2 -DGCRYPT_NO_DEPRECATED +AM_LDFLAGS = -Wl,-rpath=/lib/homegear -Wl,-rpath=/usr/lib/homegear -Wl,-rpath=/usr/local/lib/homegear +LIBS += -Wl,-Bdynamic -lhomegear-node -lhomegear-base + +libdir = $(localstatedir)/lib/homegear/node-blue/nodes/serial + +lib_LTLIBRARIES = serial-port.la serial-in.la serial-out.la + +serial_port_la_SOURCES = serial-port/Factory.cpp serial-port/MyNode.cpp +serial_port_la_LDFLAGS =-module -avoid-version -shared + +serial_in_la_SOURCES = serial-in/Factory.cpp serial-in/MyNode.cpp +serial_in_la_LDFLAGS =-module -avoid-version -shared + +serial_out_la_SOURCES = serial-out/Factory.cpp serial-out/MyNode.cpp +serial_out_la_LDFLAGS =-module -avoid-version -shared + +serial_ladir = $(libdir) +serial_la_DATA = serial-port/serial-port.hni serial-in/serial-in.hni serial-out/serial-out.hni +locale_en_usdir = $(libdir)/locales/en-US +locale_en_us_DATA = serial-port/locales/en-US/serial-port serial-in/locales/en-US/serial-in serial-out/locales/en-US/serial-out + +install-exec-hook: + rm -f $(DESTDIR)$(libdir)/serial-port.la + rm -f $(DESTDIR)$(libdir)/serial-in.la + rm -f $(DESTDIR)$(libdir)/serial-out.la diff --git a/serial/serial-in/Factory.cpp b/serial/serial-in/Factory.cpp new file mode 100644 index 00000000..6304ad24 --- /dev/null +++ b/serial/serial-in/Factory.cpp @@ -0,0 +1,42 @@ +/* Copyright 2013-2017 Sathya Laufer + * + * Homegear is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Homegear is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Homegear. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#include "Factory.h" +#include "MyNode.h" +#include "../config.h" + +Flows::INode* MyFactory::createNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected) +{ + return new MyNode::MyNode(path, nodeNamespace, type, frontendConnected); +} + +Flows::NodeFactory* getFactory() +{ + return (Flows::NodeFactory*) (new MyFactory); +} diff --git a/serial/serial-in/Factory.h b/serial/serial-in/Factory.h new file mode 100644 index 00000000..6e79b886 --- /dev/null +++ b/serial/serial-in/Factory.h @@ -0,0 +1,44 @@ +/* Copyright 2013-2017 Sathya Laufer + * + * Homegear is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Homegear is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Homegear. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#ifndef FACTORY_H +#define FACTORY_H + +#include +#include "MyNode.h" + +class MyFactory : Flows::NodeFactory +{ +public: + virtual Flows::INode* createNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected); +}; + +extern "C" Flows::NodeFactory* getFactory(); + +#endif diff --git a/serial/serial-in/MyNode.cpp b/serial/serial-in/MyNode.cpp new file mode 100644 index 00000000..22808fab --- /dev/null +++ b/serial/serial-in/MyNode.cpp @@ -0,0 +1,118 @@ +/* Copyright 2013-2017 Sathya Laufer + * + * Homegear is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Homegear is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Homegear. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#include +#include "MyNode.h" + +namespace MyNode +{ + +MyNode::MyNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected) : Flows::INode(path, nodeNamespace, type, frontendConnected) +{ + _localRpcMethods.emplace("packetReceived", std::bind(&MyNode::packetReceived, this, std::placeholders::_1)); +} + +MyNode::~MyNode() +{ +} + +bool MyNode::init(Flows::PNodeInfo info) +{ + try + { + auto settingsIterator = info->info->structValue->find("serial"); + if(settingsIterator != info->info->structValue->end()) _server = settingsIterator->second->stringValue; + + return true; + } + catch(const std::exception& ex) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return false; +} + +void MyNode::configNodesStarted() +{ + try + { + if(_server.empty()) + { + _out->printError("Error: This node has no Modbus server assigned."); + return; + } + + Flows::PArray parameters = std::make_shared(); + parameters->push_back(std::make_shared(_id)); + + Flows::PVariable result = invokeNodeMethod(_server, "registerNode", parameters, true); + if (result->errorStruct) _out->printError("Error: Could not register node: " + result->structValue->at("faultString")->stringValue); + } + catch(const std::exception& ex) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +//{{{ RPC methods + Flows::PVariable MyNode::packetReceived(Flows::PArray parameters) + { + try + { + if(parameters->size() != 1) return Flows::Variable::createError(-1, "Method expects exactly one parameter. " + std::to_string(parameters->size()) + " given."); + if(parameters->at(0)->type != Flows::VariableType::tBinary && parameters->at(0)->type != Flows::VariableType::tString) return Flows::Variable::createError(-1, "Parameter 1 is not of type String or Binary."); + + Flows::PVariable message = std::make_shared(Flows::VariableType::tStruct); + message->structValue->emplace("payload", parameters->at(0)); + + output(0, message); + + return std::make_shared(); + } + catch(const std::exception& ex) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return Flows::Variable::createError(-32500, "Unknown application error."); + } +//}}} + +} diff --git a/serial/serial-in/MyNode.h b/serial/serial-in/MyNode.h new file mode 100644 index 00000000..9deac0b3 --- /dev/null +++ b/serial/serial-in/MyNode.h @@ -0,0 +1,58 @@ +/* Copyright 2013-2017 Sathya Laufer + * + * Homegear is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Homegear is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Homegear. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#ifndef MYNODE_H_ +#define MYNODE_H_ + +#include +#include +#include + +namespace MyNode +{ + +class MyNode: public Flows::INode +{ +public: + MyNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected); + virtual ~MyNode(); + + virtual bool init(Flows::PNodeInfo info); + virtual void configNodesStarted(); +private: + std::string _server; + + //{{{ RPC methods + Flows::PVariable packetReceived(Flows::PArray parameters); + //}}} +}; + +} + +#endif diff --git a/serial/serial-in/locales/en-US/serial-in b/serial/serial-in/locales/en-US/serial-in new file mode 100644 index 00000000..d67f74f1 --- /dev/null +++ b/serial/serial-in/locales/en-US/serial-in @@ -0,0 +1,11 @@ +{ + "serial/serial-in.hni": { + "serial-in": { + "help": "

Reads data from a local serial port.

Can either

  • wait for a \"split\" character (default \n). Also accepts hex notation (0x0d).
  • Wait for a timeout in milliseconds from the first character received
  • Wait to fill a fixed sized buffer

It then outputs $message['payload'] as either a UTF8 ascii string or a binary Buffer object.

msg.port is set to the name of the port selected.

If no split character is specified, or a timeout or buffer size of 0, then a stream of single characters is sent - again either as ascii chars or size 1 binary buffers.

", + "label": { + "serialport": "Serial Port", + "serial": "serial" + } + } + } +} \ No newline at end of file diff --git a/serial/serial-in/serial-in.hni b/serial/serial-in/serial-in.hni new file mode 100644 index 00000000..c18aec74 --- /dev/null +++ b/serial/serial-in/serial-in.hni @@ -0,0 +1,53 @@ + + + + \ No newline at end of file diff --git a/serial/serial-out/Factory.cpp b/serial/serial-out/Factory.cpp new file mode 100644 index 00000000..6304ad24 --- /dev/null +++ b/serial/serial-out/Factory.cpp @@ -0,0 +1,42 @@ +/* Copyright 2013-2017 Sathya Laufer + * + * Homegear is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Homegear is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Homegear. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#include "Factory.h" +#include "MyNode.h" +#include "../config.h" + +Flows::INode* MyFactory::createNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected) +{ + return new MyNode::MyNode(path, nodeNamespace, type, frontendConnected); +} + +Flows::NodeFactory* getFactory() +{ + return (Flows::NodeFactory*) (new MyFactory); +} diff --git a/serial/serial-out/Factory.h b/serial/serial-out/Factory.h new file mode 100644 index 00000000..6e79b886 --- /dev/null +++ b/serial/serial-out/Factory.h @@ -0,0 +1,44 @@ +/* Copyright 2013-2017 Sathya Laufer + * + * Homegear is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Homegear is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Homegear. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#ifndef FACTORY_H +#define FACTORY_H + +#include +#include "MyNode.h" + +class MyFactory : Flows::NodeFactory +{ +public: + virtual Flows::INode* createNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected); +}; + +extern "C" Flows::NodeFactory* getFactory(); + +#endif diff --git a/serial/serial-out/MyNode.cpp b/serial/serial-out/MyNode.cpp new file mode 100644 index 00000000..aded94ef --- /dev/null +++ b/serial/serial-out/MyNode.cpp @@ -0,0 +1,85 @@ +/* Copyright 2013-2017 Sathya Laufer + * + * Homegear is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Homegear is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Homegear. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#include "MyNode.h" + +namespace MyNode +{ + +MyNode::MyNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected) : Flows::INode(path, nodeNamespace, type, frontendConnected) +{ +} + +MyNode::~MyNode() +{ +} + +bool MyNode::init(Flows::PNodeInfo info) +{ + try + { + auto settingsIterator = info->info->structValue->find("serial"); + if(settingsIterator != info->info->structValue->end()) _server = settingsIterator->second->stringValue; + + return true; + } + catch(const std::exception& ex) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return false; +} + +void MyNode::input(const Flows::PNodeInfo info, uint32_t index, const Flows::PVariable message) +{ + try + { + Flows::PVariable payload = std::make_shared(); + *payload = *(message->structValue->at("payload")); + + Flows::PArray parameters = std::make_shared(); + parameters->push_back(payload); + + invokeNodeMethod(_server, "write", parameters, false); + } + catch(const std::exception& ex) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +} diff --git a/serial/serial-out/MyNode.h b/serial/serial-out/MyNode.h new file mode 100644 index 00000000..229358c3 --- /dev/null +++ b/serial/serial-out/MyNode.h @@ -0,0 +1,54 @@ +/* Copyright 2013-2017 Sathya Laufer + * + * Homegear is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Homegear is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Homegear. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#ifndef MYNODE_H_ +#define MYNODE_H_ + +#include +#include + +namespace MyNode +{ + +class MyNode: public Flows::INode +{ +public: + MyNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected); + virtual ~MyNode(); + + virtual bool init(Flows::PNodeInfo info); +private: + std::string _server; + + virtual void input(const Flows::PNodeInfo info, uint32_t index, const Flows::PVariable message); +}; + +} + +#endif diff --git a/serial/serial-out/locales/en-US/serial-out b/serial/serial-out/locales/en-US/serial-out new file mode 100644 index 00000000..cf71b4f5 --- /dev/null +++ b/serial/serial-out/locales/en-US/serial-out @@ -0,0 +1,12 @@ +{ + "serial/serial-out.hni": { + "serial-out": { + "help": "

Provides a connection to an outbound serial port.

Only the $message['payload'] is sent.

Optionally the new line character used to split the input can be appended to every message sent out to the serial port.

", + "input1Description": "A binary input. The type of the binary data can be string though, too. Note that hexadecimal input is not converted to it's binary equivalent.", + "label": { + "serialport": "Serial Port", + "serial": "serial" + } + } + } +} \ No newline at end of file diff --git a/serial/serial-out/serial-out.hni b/serial/serial-out/serial-out.hni new file mode 100644 index 00000000..1a1d6d9e --- /dev/null +++ b/serial/serial-out/serial-out.hni @@ -0,0 +1,59 @@ + + + + \ No newline at end of file diff --git a/serial/serial-port/Factory.cpp b/serial/serial-port/Factory.cpp new file mode 100644 index 00000000..6304ad24 --- /dev/null +++ b/serial/serial-port/Factory.cpp @@ -0,0 +1,42 @@ +/* Copyright 2013-2017 Sathya Laufer + * + * Homegear is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Homegear is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Homegear. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#include "Factory.h" +#include "MyNode.h" +#include "../config.h" + +Flows::INode* MyFactory::createNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected) +{ + return new MyNode::MyNode(path, nodeNamespace, type, frontendConnected); +} + +Flows::NodeFactory* getFactory() +{ + return (Flows::NodeFactory*) (new MyFactory); +} diff --git a/serial/serial-port/Factory.h b/serial/serial-port/Factory.h new file mode 100644 index 00000000..6e79b886 --- /dev/null +++ b/serial/serial-port/Factory.h @@ -0,0 +1,44 @@ +/* Copyright 2013-2017 Sathya Laufer + * + * Homegear is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Homegear is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Homegear. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#ifndef FACTORY_H +#define FACTORY_H + +#include +#include "MyNode.h" + +class MyFactory : Flows::NodeFactory +{ +public: + virtual Flows::INode* createNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected); +}; + +extern "C" Flows::NodeFactory* getFactory(); + +#endif diff --git a/serial/serial-port/MyNode.cpp b/serial/serial-port/MyNode.cpp new file mode 100644 index 00000000..a6e1e34c --- /dev/null +++ b/serial/serial-port/MyNode.cpp @@ -0,0 +1,438 @@ +/* Copyright 2013-2017 Sathya Laufer + * + * Homegear is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Homegear is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Homegear. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#include "MyNode.h" + +namespace MyNode +{ + +MyNode::MyNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected) : Flows::INode(path, nodeNamespace, type, frontendConnected) +{ + _stopThread = false; + + _bl = std::make_shared(); + + _localRpcMethods.emplace("registerNode", std::bind(&MyNode::registerNode, this, std::placeholders::_1)); + _localRpcMethods.emplace("write", std::bind(&MyNode::write, this, std::placeholders::_1)); +} + +MyNode::~MyNode() +{ +} + +bool MyNode::init(Flows::PNodeInfo info) +{ + try + { + _nodeInfo = info; + return true; + } + catch(const std::exception& ex) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return false; +} + +bool MyNode::start() +{ + try + { + auto settingsIterator = _nodeInfo->info->structValue->find("serialport"); + if(settingsIterator != _nodeInfo->info->structValue->end()) _serialPort = settingsIterator->second->stringValue; + + if(_serialPort.empty()) + { + _out->printError("Error: No serial device specified."); + return false; + } + + settingsIterator = _nodeInfo->info->structValue->find("serialbaud"); + if(settingsIterator != _nodeInfo->info->structValue->end()) _baudRate = Flows::Math::getNumber(settingsIterator->second->stringValue); + + if(_baudRate <= 0) + { + _out->printError("Error: Invalid baudrate specified."); + return false; + } + + settingsIterator = _nodeInfo->info->structValue->find("databits"); + if(settingsIterator != _nodeInfo->info->structValue->end()) + { + int32_t bits = Flows::Math::getNumber(settingsIterator->second->stringValue); + + if(bits == 8) _dataBits = BaseLib::SerialReaderWriter::CharacterSize::Eight; + else if(bits == 7) _dataBits = BaseLib::SerialReaderWriter::CharacterSize::Seven; + else if(bits == 6) _dataBits = BaseLib::SerialReaderWriter::CharacterSize::Six; + else if(bits == 5) _dataBits = BaseLib::SerialReaderWriter::CharacterSize::Five; + else + { + _out->printError("Error: Invalid character size specified."); + return false; + } + } + + settingsIterator = _nodeInfo->info->structValue->find("parity"); + if(settingsIterator != _nodeInfo->info->structValue->end()) + { + _evenParity = false; + _oddParity = false; + _evenParity = (settingsIterator->second->stringValue == "even"); + _oddParity = (settingsIterator->second->stringValue == "odd"); + } + + settingsIterator = _nodeInfo->info->structValue->find("stopbits"); + if(settingsIterator != _nodeInfo->info->structValue->end()) _stopBits = Flows::Math::getNumber(settingsIterator->second->stringValue); + + settingsIterator = _nodeInfo->info->structValue->find("newline"); + if(settingsIterator != _nodeInfo->info->structValue->end()) + { + if(settingsIterator->second->stringValue.empty()) + { + _newLine = '\n'; + } + else + { + if(settingsIterator->second->stringValue.size() > 1 && Flows::Math::isNumber(settingsIterator->second->stringValue, true)) + { + _newLine = (char)(uint8_t)Flows::Math::getNumber(settingsIterator->second->stringValue, true); + } + else if(settingsIterator->second->stringValue.size() == 2) + { + switch(settingsIterator->second->stringValue.at(1)) + { + case 'b': + _newLine = '\b'; + break; + case 'f': + _newLine = '\f'; + break; + case 'n': + _newLine = '\n'; + break; + case 'r': + _newLine = '\r'; + break; + case 't': + _newLine = '\t'; + break; + default: + _newLine = settingsIterator->second->stringValue.front(); + } + } + else _newLine = settingsIterator->second->stringValue.front(); + } + _timeout = Flows::Math::getNumber(settingsIterator->second->stringValue); + if(_timeout < 0) _timeout = 1; + else if(_timeout > 5000) _timeout = 5000; + _fixedCount = Flows::Math::getNumber(settingsIterator->second->stringValue); + if(_fixedCount < 1) _fixedCount = 1; + } + + settingsIterator = _nodeInfo->info->structValue->find("bin"); + if(settingsIterator != _nodeInfo->info->structValue->end()) _binaryOutput = settingsIterator->second->booleanValue; + + settingsIterator = _nodeInfo->info->structValue->find("out"); + if(settingsIterator != _nodeInfo->info->structValue->end()) + { + std::string& splitType = settingsIterator->second->stringValue; + if(splitType == "no") _splitType = SplitType::no; + else if(splitType == "char") _splitType = SplitType::character; + else if(splitType == "time") _splitType = SplitType::timeout; + else if(splitType == "count") _splitType = SplitType::fixedLength; + } + + settingsIterator = _nodeInfo->info->structValue->find("addchar"); + if(settingsIterator != _nodeInfo->info->structValue->end()) _addCharacter = settingsIterator->second->booleanValue; + + _serial = std::make_shared(_bl.get(), _serialPort, _baudRate, 0, true, -1); + reopen(); + + _stopThread = false; + _bl->threadManager.start(_readThread, true, &MyNode::listenThread, this); + + return true; + } + catch(const std::exception& ex) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return false; +} + +void MyNode::stop() +{ + try + { + _stopThread = true; + } + catch(const std::exception& ex) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +void MyNode::waitForStop() +{ + try + { + _stopThread = true; + _bl->threadManager.join(_readThread); + } + catch(const std::exception& ex) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +Flows::PVariable MyNode::getConfigParameterIncoming(std::string name) +{ + try + { + auto settingsIterator = _nodeInfo->info->structValue->find(name); + if(settingsIterator != _nodeInfo->info->structValue->end()) return settingsIterator->second; + } + catch(const std::exception& ex) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return std::make_shared(); +} + +void MyNode::reopen() +{ + try + { + _serial->closeDevice(); + _serial->openDevice(_evenParity, _oddParity, false, _dataBits, _stopBits == 2); + } + catch(const std::exception& ex) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +void MyNode::packetReceived(Flows::PVariable data) +{ + try + { + Flows::PArray parameters = std::make_shared(); + parameters->push_back(data); + std::lock_guard nodesGuard(_nodesMutex); + for (auto& node : _nodes) + { + invokeNodeMethod(node, "packetReceived", parameters, false); + } + } + catch(const std::exception& ex) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +void MyNode::listenThread() +{ + while(!_stopThread) + { + try + { + int32_t readBytes = 0; + if(_splitType == SplitType::character) + { + std::string data; + readBytes = _serial->readLine(data, 500000, _newLine); + + if(readBytes == 0) + { + if(_binaryOutput) + { + std::vector buffer(data.begin(), data.end()); + packetReceived(std::make_shared(buffer)); + } + else packetReceived(std::make_shared(BaseLib::HelperFunctions::getHexString(data))); + } + } + else if(_splitType == SplitType::no) + { + char data; + readBytes = _serial->readChar(data); + + if(readBytes == 0) + { + if(_binaryOutput) + { + std::vector buffer{data}; + packetReceived(std::make_shared(buffer)); + } + else packetReceived(std::make_shared(BaseLib::HelperFunctions::getHexString(std::string{data}))); + } + } + else if(_splitType == SplitType::timeout) + { + std::vector buffer; + buffer.reserve(1024); + char data; + readBytes = 0; + while(readBytes == 0) + { + readBytes = _serial->readChar(data, _timeout * 1000); + if(readBytes == 0) + { + if(buffer.size() + 1 > buffer.capacity()) buffer.reserve(buffer.capacity() + 1024); + buffer.push_back(data); + } + } + + if(!buffer.empty()) + { + if(_binaryOutput) packetReceived(std::make_shared(buffer)); + else packetReceived(std::make_shared(BaseLib::HelperFunctions::getHexString(buffer))); + } + } + else if(_splitType == SplitType::fixedLength) + { + std::vector buffer(_dataBuffer.begin(), _dataBuffer.end()); + buffer.reserve(1024); + char data; + readBytes = 1; + while(readBytes > 0) + { + readBytes = _serial->readChar(data); + if(readBytes == 0) + { + if(buffer.size() + 1 > buffer.capacity()) buffer.reserve(buffer.capacity() + 1024); + buffer.push_back(data); + + if(buffer.size() >= (unsigned)_fixedCount) + { + if(_binaryOutput) packetReceived(std::make_shared(buffer)); + else packetReceived(std::make_shared(BaseLib::HelperFunctions::getHexString(buffer))); + } + } + else if(readBytes == 1) + { + _dataBuffer.clear(); + _dataBuffer.insert(_dataBuffer.end(), buffer.begin(), buffer.end()); + } + } + } + + if(readBytes == -1) reopen(); + } + catch(const std::exception& ex) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + } +} + +//{{{ RPC methods +Flows::PVariable MyNode::registerNode(Flows::PArray parameters) +{ + try + { + if(parameters->size() != 1) return Flows::Variable::createError(-1, "Method expects exactly one parameter. " + std::to_string(parameters->size()) + " given."); + if(parameters->at(0)->type != Flows::VariableType::tString || parameters->at(0)->stringValue.empty()) return Flows::Variable::createError(-1, "Parameter is not of type string."); + + std::lock_guard nodesGuard(_nodesMutex); + _nodes.emplace(parameters->at(0)->stringValue); + + return std::make_shared(); + } + catch(const std::exception& ex) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return Flows::Variable::createError(-32500, "Unknown application error."); +} + +Flows::PVariable MyNode::write(Flows::PArray parameters) +{ + try + { + if(parameters->size() != 1) return Flows::Variable::createError(-1, "Method expects exactly one parameter."); + if(parameters->at(0)->type != Flows::VariableType::tString && parameters->at(0)->type != Flows::VariableType::tBinary) return Flows::Variable::createError(-1, "Parameter is not of type Binary or String."); + if(parameters->at(0)->binaryValue.empty() && parameters->at(0)->stringValue.empty()) return Flows::Variable::createError(-1, "No data given."); + + + if(parameters->at(0)->type == Flows::VariableType::tString) parameters->at(0)->binaryValue.insert(parameters->at(0)->binaryValue.end(), parameters->at(0)->stringValue.begin(), parameters->at(0)->stringValue.end()); + if(_addCharacter && _splitType == SplitType::character) parameters->at(0)->binaryValue.push_back(_newLine); + _serial->writeData(parameters->at(0)->binaryValue); + + return std::make_shared(); + } + catch(const std::exception& ex) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return Flows::Variable::createError(-32500, "Unknown application error."); +} +//}}} + +} diff --git a/serial/serial-port/MyNode.h b/serial/serial-port/MyNode.h new file mode 100644 index 00000000..fa74ca84 --- /dev/null +++ b/serial/serial-port/MyNode.h @@ -0,0 +1,98 @@ +/* Copyright 2013-2017 Sathya Laufer + * + * Homegear is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Homegear is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Homegear. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#ifndef MYNODE_H_ +#define MYNODE_H_ + +#include +#include + +namespace MyNode +{ + +class MyNode: public Flows::INode +{ +public: + MyNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected); + virtual ~MyNode(); + + virtual bool init(Flows::PNodeInfo info); + virtual bool start(); + virtual void stop(); + virtual void waitForStop(); + + virtual Flows::PVariable getConfigParameterIncoming(std::string name); +private: + enum class SplitType + { + no, + character, + timeout, + fixedLength + }; + + Flows::PNodeInfo _nodeInfo; + + std::mutex _nodesMutex; + std::set _nodes; + + std::shared_ptr _bl; + std::shared_ptr _serial; + std::atomic_bool _stopThread; + std::thread _readThread; + std::vector _dataBuffer; + + //{{{ Settings + std::string _serialPort; + int32_t _baudRate = 57600; + BaseLib::SerialReaderWriter::CharacterSize _dataBits = BaseLib::SerialReaderWriter::CharacterSize::Eight; + bool _evenParity = false; + bool _oddParity = false; + int32_t _stopBits = 1; + char _newLine = '\n'; + int32_t _timeout = 0; + int32_t _fixedCount = 1; + bool _binaryOutput = true; + SplitType _splitType; + bool _addCharacter = false; + //}}} + + void listenThread(); + void reopen(); + void packetReceived(Flows::PVariable data); + + //{{{ RPC methods + Flows::PVariable registerNode(Flows::PArray parameters); + Flows::PVariable write(Flows::PArray parameters); + //}}} +}; + +} + +#endif diff --git a/serial/serial-port/locales/en-US/serial-port b/serial/serial-port/locales/en-US/serial-port new file mode 100644 index 00000000..f348937b --- /dev/null +++ b/serial/serial-port/locales/en-US/serial-port @@ -0,0 +1,43 @@ +{ + "serial/serial-port.hni": { + "serial-port": { + "help": "

Provides configuration options for a serial port.

The input can be split on a fixed character, after a timeout, or after a fixed number of characters.

If using a character, it can be specified as either the character, the escaped shortcut (e.g. \n), or the hex code (e.g. 0x0d).

", + "label": { + "serialport": "Serial Port", + "settings": "Settings", + "baudrate": "Baud Rate", + "databits": "Data Bits", + "parity": "Parity", + "stopbits": "Stop Bits", + "input": "Input", + "split": "Split input", + "deliver": "and deliver", + "output": "Output", + "none": "none" + }, + "placeholder": { + "serialport": "for example: /dev/ttyUSB0/" + }, + "parity": { + "none": "None", + "even": "Even", + "odd": "Odd" + }, + "split": { + "no": "no", + "character": "on the character", + "timeout": "after a timeout of", + "lengths": "into fixed lengths of" + }, + "output": { + "ascii": "ascii strings", + "binary": "binary buffers" + }, + "addsplit": "add split character to output messages", + "tip": { + "split": "Tip: the \"Split on\" character is used to split the input into separate messages. It can also be added to every message sent out to the serial port.", + "timeout": "Tip: In timeout mode timeout starts from arrival of first character." + } + } + } +} \ No newline at end of file diff --git a/serial/serial-port/serial-port.hni b/serial/serial-port/serial-port.hni new file mode 100644 index 00000000..4a101c81 --- /dev/null +++ b/serial/serial-port/serial-port.hni @@ -0,0 +1,187 @@ + + + + \ No newline at end of file diff --git a/variable/constant/MyNode.cpp b/variable/constant/MyNode.cpp index a140bb29..be15c6db 100644 --- a/variable/constant/MyNode.cpp +++ b/variable/constant/MyNode.cpp @@ -44,40 +44,40 @@ bool MyNode::init(Flows::PNodeInfo info) { try { - std::string payloadType = "int"; + _payloadType = "int"; auto settingsIterator = info->info->structValue->find("payloadType"); - if(settingsIterator != info->info->structValue->end()) payloadType = settingsIterator->second->stringValue; + if(settingsIterator != info->info->structValue->end()) _payloadType = settingsIterator->second->stringValue; std::string payload; settingsIterator = info->info->structValue->find("payload"); if(settingsIterator != info->info->structValue->end()) payload = settingsIterator->second->stringValue; _value = std::make_shared(); - if(payloadType == "bool") + if(_payloadType == "bool") { _value->setType(Flows::VariableType::tBoolean); _value->booleanValue = payload == "true"; } - else if(payloadType == "int") + else if(_payloadType == "int") { _value->setType(Flows::VariableType::tInteger64); _value->integerValue64 = Flows::Math::getNumber64(payload); _value->integerValue = (int32_t)_value->integerValue64; _value->floatValue = _value->integerValue64; } - else if(payloadType == "float") + else if(_payloadType == "float") { _value->setType(Flows::VariableType::tFloat); _value->floatValue = Flows::Math::getDouble(payload); _value->integerValue = _value->floatValue; _value->integerValue64 = _value->floatValue; } - else if(payloadType == "string") + else if(_payloadType == "string") { _value->setType(Flows::VariableType::tString); _value->stringValue = payload; } - else if(payloadType == "array" || payloadType == "struct") + else if(_payloadType == "array" || _payloadType == "struct") { Flows::JsonDecoder jsonDecoder; _value = jsonDecoder.decode(payload); @@ -121,4 +121,32 @@ void MyNode::startUpComplete() } } +void MyNode::setNodeVariable(std::string variable, Flows::PVariable value) +{ + try + { + if(variable == "nodeOutput" && value) + { + if(_payloadType == "float" && value->type != Flows::VariableType::tFloat) + { + value->type = Flows::VariableType::tFloat; + value->floatValue = value->integerValue64; + } + + Flows::PVariable message = std::make_shared(Flows::VariableType::tStruct); + message->structValue->emplace("payload", value); + + output(0, message); + } + } + catch(const std::exception& ex) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + } diff --git a/variable/constant/MyNode.h b/variable/constant/MyNode.h index ea28e8b2..91a6dc7f 100644 --- a/variable/constant/MyNode.h +++ b/variable/constant/MyNode.h @@ -44,8 +44,10 @@ class MyNode: public Flows::INode virtual bool init(Flows::PNodeInfo info); virtual void startUpComplete(); + virtual void setNodeVariable(std::string variable, Flows::PVariable value); private: bool _outputOnStartup = true; + std::string _payloadType; Flows::PVariable _value; }; diff --git a/variable/constant/constant.hni b/variable/constant/constant.hni index 75b46972..15f07786 100644 --- a/variable/constant/constant.hni +++ b/variable/constant/constant.hni @@ -85,7 +85,7 @@ else if (this.payloadType == 'float') value = parseFloat(this.payload); else if (this.payloadType == 'array' || this.payloadType == 'struct') value = JSON.parse(this.payload); else value = this.payload; - RED.comms.homegear().invoke("nodeOutput", null, this.id, 0, {'payload': value}); + RED.comms.homegear().invoke('setNodeVariable', null, this.id, "nodeOutput", value); } } });