diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..514148b --- /dev/null +++ b/.gitignore @@ -0,0 +1,79 @@ +# Compiled Object files +*.slo +*.lo +*.o +*.obj +# Precompiled Headers +*.gch +*.pch +# Compiled Dynamic libraries +*.so +*.so.1.0.0 +*.dylib +*.dll +# Fortran module files +*.mod +# Compiled Static libraries +*.lai +*.la +*.a +*.lib +# Executables +*.exe +*.out +*.app + +*.pydevproject +.metadata +.gradle +lib/ +bin/ +obj/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +# External tool builders +.externalToolBuilders/ +# Locally stored "Eclipse launch configurations" +*.launch +# CDT-specific +.cproject +# PDT-specific +.buildpath +# sbteclipse plugin +.target +# TeXlipse plugin +.texlipse +autom4te.cache +*.in~ +config.log +homegear +core +vgcore.* + +#Autotools +autoscan.* +Makefile +Makefile.in +aclocal.m4 +autom4te.cache/ +config.* +configure +depcomp +install-sh +libtool +ltmain.sh +cfg/ +m4/ +missing +stamp-h? +.deps/ +.dirstamp +.libs/ +*.l[ao] +*~ diff --git a/.project b/.project new file mode 100644 index 0000000..de382b3 --- /dev/null +++ b/.project @@ -0,0 +1,41 @@ + + + homegear-enocean + + + + + + org.eclipse.ui.externaltools.ExternalToolBuilder + full,incremental, + + + LaunchConfigHandle + <project>/.externalToolBuilders/org.eclipse.cdt.managedbuilder.core.genmakebuilder (13).launch + + + + + org.eclipse.ui.externaltools.ExternalToolBuilder + full,incremental, + + + LaunchConfigHandle + <project>/.externalToolBuilders/homegear-intertechno-builder.launch + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..6067ea9 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,3 @@ +AUTOMAKE_OPTIONS = foreign +ACLOCAL_AMFLAGS = -I m4 -I cfg +SUBDIRS = src diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/bootstrap b/bootstrap new file mode 100755 index 0000000..a36d6be --- /dev/null +++ b/bootstrap @@ -0,0 +1,7 @@ +#!/bin/sh +libtoolize || exit 1 +aclocal || exit 1 +autoheader || exit 1 +automake --add-missing || exit 1 +autoconf || exit 1 +#./configure --prefix=/usr --localstatedir=/var --sysconfdir=/etc --libdir=/usr/lib || exit 1 diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..22c79f3 --- /dev/null +++ b/configure.ac @@ -0,0 +1,65 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.69]) +AC_INIT(homegar-intertechno, m4_esyscmd_s([./getVersion.sh]), sathya@laufers.net) +AC_CONFIG_AUX_DIR(cfg) +AM_INIT_AUTOMAKE +AC_CONFIG_SRCDIR([src/MyFamily.h]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) +AC_PREFIX_DEFAULT(/usr) + +dnl AM_MAINTAINER_MODE + +# Checks for programs. +AC_PROG_CXX +AC_PROG_CC +AC_PROG_INSTALL + +# Libraries +LT_INIT + +# Checks for header files. +AC_CHECK_HEADERS([stdlib.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_CHECK_HEADER_STDBOOL +AC_C_INLINE +AC_C_CONST +AC_TYPE_INT32_T +AC_TYPE_INT64_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T +AC_TYPE_UINT32_T +AC_TYPE_UINT64_T +AC_TYPE_UINT8_T +AC_TYPE_SIZE_T + +# Checks for library functions. +AC_FUNC_CHOWN +AC_FUNC_ERROR_AT_LINE +AC_FUNC_FORK +AC_CHECK_FUNCS([floor memchr memset pow select socket strchr strerror strstr strtol]) + +AC_CANONICAL_HOST +case $host_os in + darwin* ) + CPPFLAGS="$CPPFLAGS -DMACOSSYSTEM" + ;; + linux*) + CPPFLAGS="$CPPFLAGS -DLINUXSYSTEM" + ;; + *BSD*) + CPPFLAGS="$CPPFLAGS -DBSDSYSTEM -D_GLIBCXX_USE_C99 -D_GLIBCXX_USE_C99_MATH -D_GLIBCXX_USE_C99_MATH_TR1 -D_WITH_DPRINTF" + ;; + *) + AC_MSG_ERROR([Your platform is not currently supported]) + ;; +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 src/Makefile) diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..d72e46a --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +homegear-intertechno (0.0.1-1) UNRELEASED; urgency=low + + * Initial release. + + -- Sathya Laufer Sat, 17 Aug 2013 12:00:47 +0200 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..45a4fb7 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +8 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..53713ca --- /dev/null +++ b/debian/control @@ -0,0 +1,14 @@ +Source: homegear-intertechno +Maintainer: Sathya Laufer +Section: misc +Priority: optional +Standards-Version: 3.9.6 +Build-Depends: debhelper (>= 8), libhomegear-base (= ), libgcrypt20-dev, libgpg-error-dev (>= 1.10), libgnutls28-dev +Homepage: https://homegear.eu + +Package: homegear-intertechno +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, libhomegear-base (= ), homegear (= ), libgcrypt20, libgnutlsxx28, libgpg-error0 (>= 1.10) +Description: Intertechno module for Homegear + Homegear is a program to interface your home automation software + with your smart home devices. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..ce5ec21 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,36 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: homegear-intertechno +Upstream-Contact: Sathya Laufer + +Files: * +Copyright: 2013-2016 Sathya Laufer +License: GPL-3+ + 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 . + . + On Debian systems, the full text of the GNU General Public + License version 3 can be found in the file + `/usr/share/common-licenses/GPL-3'. + . + 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. diff --git a/debian/postinst b/debian/postinst new file mode 100644 index 0000000..87e1bd7 --- /dev/null +++ b/debian/postinst @@ -0,0 +1,46 @@ +#!/bin/sh + +case $1 in + # Configure this package. If the package must prompt the user for + # information, do it here. + configure) + chown -R homegear:homegear /var/lib/homegear/modules + chmod -R 550 /var/lib/homegear/modules + homegear -e mls > /dev/null 2>&1 + if [ $? -eq 0 ]; then + homegear -e mld mod_intertechno.so + fi + echo "##########################################################################" + echo "##########################################################################" + echo "### Please modify the file /etc/homegear/families/intertechno.conf ###" + echo "### according to your needs and restart Homegear. ###" + echo "##########################################################################" + echo "##########################################################################" + ;; + + # Back out of an attempt to upgrade this package FROM THIS VERSION + # to version $2. Undo the effects of "prerm upgrade $2". + abort-upgrade) + ;; + + # Back out of an attempt to remove this package, which was due to + # a conflict with package $3 (version $4). Undo the effects of + # "prerm remove in-favour $3 $4". + abort-remove) + ;; + + # Back out of an attempt to deconfigure this package, which was + # due to package $6 (version $7) which we depend on being removed + # to make way for package $3 (version $4). Undo the effects of + # "prerm deconfigure in-favour $3 $4 removing $6 $7". + abort-deconfigure) + ;; + + *) + echo "$0: didn't understand being called with \`$1'" 1>&2 + exit 1; + ;; + +esac + +#DEBHELPER# diff --git a/debian/postrm b/debian/postrm new file mode 100644 index 0000000..9cade8e --- /dev/null +++ b/debian/postrm @@ -0,0 +1,30 @@ +#!/bin/sh + +case "$1" in + remove|abort-install|abort-upgrade) + # This package is being removed, but its configuration has not yet + # been purged. + + ;; + + purge) + rm -Rf /etc/homegear/devices/16 > /dev/null 2>&1 + rm -f /var/lib/homegear/modules/mod_intertechno.so > /dev/null 2>&1 + ;; + + disappear) + ;; + + upgrade) + ;; + + failed-upgrade) + ;; + + *) echo "$0: didn't understand being called with \`$1'" 1>&2 + exit 1;; +esac + +exit 0 + +#DEBHELPER# diff --git a/debian/preinst b/debian/preinst new file mode 100644 index 0000000..357d8e9 --- /dev/null +++ b/debian/preinst @@ -0,0 +1,15 @@ +#!/bin/sh +set -e + +case "$1" in + install) + ;; + + upgrade|abort-upgrade) + service homegear stop + ;; +esac + +#DEBHELPER# + +exit 0 \ No newline at end of file diff --git a/debian/prerm b/debian/prerm new file mode 100644 index 0000000..728ede3 --- /dev/null +++ b/debian/prerm @@ -0,0 +1,25 @@ +#!/bin/sh + +case "$1" in + remove|purge|abort-install|abort-upgrade) + # This package is being removed, but its configuration has not yet + # been purged. + service homegear stop + ;; + + disappear) + ;; + + upgrade) + ;; + + failed-upgrade) + ;; + + *) echo "$0: didn't understand being called with \`$1'" 1>&2 + exit 1;; +esac + +exit 0 + +#DEBHELPER# diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..5e0417e --- /dev/null +++ b/debian/rules @@ -0,0 +1,20 @@ +#!/usr/bin/make -f + +override_dh_auto_install: + dh_auto_install + + mkdir -p $(CURDIR)/debian/homegear-intertechno/etc/homegear/families + cp -R $(CURDIR)/misc/Config\ Directory/* $(CURDIR)/debian/homegear-intertechno/etc/homegear/families + chmod 755 $(CURDIR)/debian/homegear-intertechno/etc/homegear/families + chmod 644 $(CURDIR)/debian/homegear-intertechno/etc/homegear/families/* + + mkdir -p $(CURDIR)/debian/homegear-intertechno/etc/homegear/devices/16 + cp $(CURDIR)/misc/Device\ Description\ Files/* $(CURDIR)/debian/homegear-intertechno/etc/homegear/devices/16 + chmod 755 $(CURDIR)/debian/homegear-intertechno/etc/homegear/devices/16 + chmod 644 $(CURDIR)/debian/homegear-intertechno/etc/homegear/devices/16/* + +override_dh_strip: + dh_strip --dbg-package=homegear-intertechno + +%: + dh $@ --parallel diff --git a/debian/source.lintian-overrides b/debian/source.lintian-overrides new file mode 100644 index 0000000..e69de29 diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/getVersion.sh b/getVersion.sh new file mode 100755 index 0000000..a33c9b5 --- /dev/null +++ b/getVersion.sh @@ -0,0 +1,15 @@ +#!/bin/sh +dir=`mktemp -d` +cat > "$dir/libhomegear-base-version.cpp" <<-'EOF' +#include "homegear-base/BaseLib.h" + +int main(int argc, char** argv) +{ + std::cout << BaseLib::Obj::version() << std::endl; + return 0; +} +EOF +g++ -std=c++11 -o $dir/libhomegear-base-version $dir/libhomegear-base-version.cpp -lhomegear-base -lgcrypt -lgnutls +chmod 755 $dir/libhomegear-base-version +$dir/libhomegear-base-version +rm -Rf $dir diff --git a/makeDebug.sh b/makeDebug.sh new file mode 100755 index 0000000..793050c --- /dev/null +++ b/makeDebug.sh @@ -0,0 +1,13 @@ +#!/bin/bash +if [ -n "$1" ]; then + BUILDTHREADS=$1 +else + BUILDTHREADS=2 +fi + +SCRIPTDIR="$( cd "$(dirname $0)" && pwd )" +cd $SCRIPTDIR +rm -Rf autom4te.cache +./bootstrap || exit 1 +./configure --prefix=/usr --localstatedir=/var --sysconfdir=/etc --libdir=/usr/lib || exit 1 +CPPFLAGS=-DDEBUG CXXFLAGS="-g -O0" && make -j${BUILDTHREADS} && make install diff --git a/makeRelease.sh b/makeRelease.sh new file mode 100755 index 0000000..1a63dcc --- /dev/null +++ b/makeRelease.sh @@ -0,0 +1,14 @@ +#!/bin/bash +if [ -n "$1" ]; then + BUILDTHREADS=$1 +else + BUILDTHREADS=2 +fi +SCRIPTDIR="$( cd "$(dirname $0)" && pwd )" +cd $SCRIPTDIR +rm -Rf autom4te.cache +./bootstrap || exit 1 +./configure --prefix=/usr --localstatedir=/var --sysconfdir=/etc --libdir=/usr/lib || exit 1 +make -j${BUILDTHREADS} || exit 1 +strip -s src/.libs/mod_enocean.so +make install diff --git a/misc/Config Directory/intertechno.conf b/misc/Config Directory/intertechno.conf new file mode 100644 index 0000000..6560d66 --- /dev/null +++ b/misc/Config Directory/intertechno.conf @@ -0,0 +1,42 @@ +___________________________________________________________________________ + +------------------------------- Intertechno ------------------------------- +___________________________________________________________________________ + +####################################### +################# CUL ################# +####################################### + +## The device family this interface is for +#[CUL] + +## Specify an unique id here to identify this device in Homegear +#id = My-IT-CUL-1 + +## When default is set to "true" Homegear will assign this device +## to new peers. +#default = true + +## Options: cul, coc, cc1100 +#deviceType = cul + +#device = /dev/ttyACM0 + +####################################### +################# CUL ################# +####################################### + +## The device family this interface is for +#[CUL] + +## Specify an unique id here to identify this device in Homegear +#id = My-IT-CUL-2 + +## When default is set to "true" Homegear will assign this device +## to new peers. +#default = true + +## Options: cul, coc, cc1100 +#deviceType = cul + +#device = /dev/ttyACM1 diff --git a/misc/Device Description Files/Switch.xml b/misc/Device Description Files/Switch.xml new file mode 100644 index 0000000..9f858b5 --- /dev/null +++ b/misc/Device Description Files/Switch.xml @@ -0,0 +1,100 @@ + + + + + Intertechno Switch + 1 + + + + + + true + + IntertechnoConfig + maint_ch_values + + + IntertechnoVariables + + + + + + + + true + false + true + + + + internal + + + + + true + true + true + true + + + + internal + + + + + false + + + + internal + + + + + + + false + true + + + + command + + + + + false + true + + + + command + + + + + true + true + + + + command + + + + + false + true + + + + command + + + + + diff --git a/src/Factory.cpp b/src/Factory.cpp new file mode 100644 index 0000000..d9a6f37 --- /dev/null +++ b/src/Factory.cpp @@ -0,0 +1,57 @@ +/* Copyright 2013-2016 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 "../config.h" +#include "GD.h" + +BaseLib::Systems::DeviceFamily* MyFactory::createDeviceFamily(BaseLib::Obj* bl, BaseLib::Systems::DeviceFamily::IFamilyEventSink* eventHandler) +{ + return new MyFamily::MyFamily(bl, eventHandler); +} + +std::string getVersion() +{ + return VERSION; +} + +int32_t getFamilyId() +{ + return MY_FAMILY_ID; +} + +std::string getFamilyName() +{ + return MY_FAMILY_NAME; +} + +BaseLib::Systems::SystemFactory* getFactory() +{ + return (BaseLib::Systems::SystemFactory*)(new MyFactory); +} diff --git a/src/Factory.h b/src/Factory.h new file mode 100644 index 0000000..cf660f1 --- /dev/null +++ b/src/Factory.h @@ -0,0 +1,47 @@ +/* Copyright 2013-2016 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 "MyFamily.h" + +class MyFactory : BaseLib::Systems::SystemFactory +{ +public: + virtual BaseLib::Systems::DeviceFamily* createDeviceFamily(BaseLib::Obj* bl, BaseLib::Systems::DeviceFamily::IFamilyEventSink* eventHandler); +}; + +extern "C" std::string getVersion(); +extern "C" int32_t getFamilyId(); +extern "C" std::string getFamilyName(); +extern "C" BaseLib::Systems::SystemFactory* getFactory(); + +#endif diff --git a/src/GD.cpp b/src/GD.cpp new file mode 100644 index 0000000..da07751 --- /dev/null +++ b/src/GD.cpp @@ -0,0 +1,39 @@ +/* Copyright 2013-2016 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 "GD.h" + +namespace MyFamily +{ + BaseLib::Obj* GD::bl = nullptr; + MyFamily* GD::family = nullptr; + std::map> GD::physicalInterfaces; + std::shared_ptr GD::defaultPhysicalInterface; + BaseLib::Output GD::out; +} diff --git a/src/GD.h b/src/GD.h new file mode 100644 index 0000000..499b5ab --- /dev/null +++ b/src/GD.h @@ -0,0 +1,59 @@ +/* Copyright 2013-2016 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 GD_H_ +#define GD_H_ + +#define MY_FAMILY_ID 16 +#define MY_FAMILY_NAME "Intertechno" + +#include +#include "MyFamily.h" +#include "PhysicalInterfaces/IIntertechnoInterface.h" + +namespace MyFamily +{ + +class GD +{ +public: + virtual ~GD(); + + static BaseLib::Obj* bl; + static MyFamily* family; + static std::map> physicalInterfaces; + static std::shared_ptr defaultPhysicalInterface; + static BaseLib::Output out; +private: + GD(); +}; + +} + +#endif /* GD_H_ */ diff --git a/src/Interfaces.cpp b/src/Interfaces.cpp new file mode 100644 index 0000000..c76b11e --- /dev/null +++ b/src/Interfaces.cpp @@ -0,0 +1,80 @@ +/* Copyright 2013-2016 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 "Interfaces.h" +#include "GD.h" +#include "PhysicalInterfaces/Cul.h" + +namespace MyFamily +{ + +Interfaces::Interfaces(BaseLib::Obj* bl, std::map physicalInterfaceSettings) : Systems::PhysicalInterfaces(bl, GD::family->getFamily(), physicalInterfaceSettings) +{ + create(); +} + +Interfaces::~Interfaces() +{ +} + +void Interfaces::create() +{ + try + { + for(std::map::iterator i = _physicalInterfaceSettings.begin(); i != _physicalInterfaceSettings.end(); ++i) + { + std::shared_ptr device; + if(!i->second) continue; + GD::out.printDebug("Debug: Creating physical device. Type defined in intertechno.conf is: " + i->second->type); + if(i->second->type == "cul") device.reset(new Cul(i->second)); + else GD::out.printError("Error: Unsupported physical device type: " + i->second->type); + if(device) + { + if(_physicalInterfaces.find(i->second->id) != _physicalInterfaces.end()) GD::out.printError("Error: id used for two devices: " + i->second->id); + _physicalInterfaces[i->second->id] = device; + GD::physicalInterfaces[i->second->id] = device; + if(i->second->isDefault || !GD::defaultPhysicalInterface) GD::defaultPhysicalInterface = device; + } + } + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +} diff --git a/src/Interfaces.h b/src/Interfaces.h new file mode 100644 index 0000000..a2a9e38 --- /dev/null +++ b/src/Interfaces.h @@ -0,0 +1,52 @@ +/* Copyright 2013-2016 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 INTERFACES_H_ +#define INTERFACES_H_ + +#include + +namespace MyFamily +{ + +using namespace BaseLib; + +class Interfaces : public BaseLib::Systems::PhysicalInterfaces +{ +public: + Interfaces(BaseLib::Obj* bl, std::map physicalInterfaceSettings); + virtual ~Interfaces(); + +protected: + virtual void create(); +}; + +} + +#endif diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..26262a6 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,12 @@ +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 + +libdir = $(localstatedir)/lib/homegear/modules +lib_LTLIBRARIES = mod_intertechno.la +mod_intertechno_la_SOURCES = MyFamily.cpp MyFamily.h MyPacket.cpp MyPacket.h MyPeer.cpp MyPeer.h Factory.cpp Factory.h GD.cpp GD.h MyCentral.cpp MyCentral.h Interfaces.h Interfaces.cpp PhysicalInterfaces/IIntertechnoInterface.h PhysicalInterfaces/IIntertechnoInterface.cpp PhysicalInterfaces/Cul.h PhysicalInterfaces/Cul.cpp +mod_intertechno_la_LDFLAGS =-module -avoid-version -shared +install-exec-hook: + rm -f $(DESTDIR)$(libdir)/mod_intertechno.la diff --git a/src/MyCentral.cpp b/src/MyCentral.cpp new file mode 100644 index 0000000..68e758f --- /dev/null +++ b/src/MyCentral.cpp @@ -0,0 +1,948 @@ +/* Copyright 2013-2016 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 "MyCentral.h" +#include "GD.h" + +namespace MyFamily { + +MyCentral::MyCentral(ICentralEventSink* eventHandler) : BaseLib::Systems::ICentral(MY_FAMILY_ID, GD::bl, eventHandler) +{ + init(); +} + +MyCentral::MyCentral(uint32_t deviceID, std::string serialNumber, ICentralEventSink* eventHandler) : BaseLib::Systems::ICentral(MY_FAMILY_ID, GD::bl, deviceID, serialNumber, -1, eventHandler) +{ + init(); +} + +MyCentral::~MyCentral() +{ + dispose(); +} + +void MyCentral::dispose(bool wait) +{ + try + { + if(_disposing) return; + _disposing = true; + GD::out.printDebug("Removing device " + std::to_string(_deviceId) + " from physical device's event queue..."); + for(std::map>::iterator i = GD::physicalInterfaces.begin(); i != GD::physicalInterfaces.end(); ++i) + { + //Just to make sure cycle through all physical devices. If event handler is not removed => segfault + i->second->removeEventHandler(_physicalInterfaceEventhandlers[i->first]); + } + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +void MyCentral::init() +{ + try + { + if(_initialized) return; //Prevent running init two times + _initialized = true; + + for(std::map>::iterator i = GD::physicalInterfaces.begin(); i != GD::physicalInterfaces.end(); ++i) + { + _physicalInterfaceEventhandlers[i->first] = i->second->addEventHandler((BaseLib::Systems::IPhysicalInterface::IPhysicalInterfaceEventSink*)this); + } + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +void MyCentral::loadPeers() +{ + try + { + std::shared_ptr rows = _bl->db->getPeers(_deviceId); + for(BaseLib::Database::DataTable::iterator row = rows->begin(); row != rows->end(); ++row) + { + int32_t peerID = row->second.at(0)->intValue; + GD::out.printMessage("Loading Intertechno peer " + std::to_string(peerID)); + std::shared_ptr peer(new MyPeer(peerID, row->second.at(2)->intValue, row->second.at(3)->textValue, _deviceId, this)); + if(!peer->load(this)) continue; + if(!peer->getRpcDevice()) continue; + std::lock_guard peersGuard(_peersMutex); + if(!peer->getSerialNumber().empty()) _peersBySerial[peer->getSerialNumber()] = peer; + _peersById[peerID] = peer; + _peers[peer->getAddress()] = peer; + } + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +std::shared_ptr MyCentral::getPeer(uint64_t id) +{ + try + { + std::lock_guard peersGuard(_peersMutex); + if(_peersById.find(id) != _peersById.end()) + { + std::shared_ptr peer(std::dynamic_pointer_cast(_peersById.at(id))); + return peer; + } + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return std::shared_ptr(); +} + +std::shared_ptr MyCentral::getPeer(int32_t address) +{ + try + { + std::lock_guard peersGuard(_peersMutex); + if(_peers.find(address) != _peers.end()) + { + std::shared_ptr peer(std::dynamic_pointer_cast(_peers.at(address))); + return peer; + } + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return std::shared_ptr(); +} + +std::shared_ptr MyCentral::getPeer(std::string serialNumber) +{ + try + { + std::lock_guard peersGuard(_peersMutex); + if(_peersBySerial.find(serialNumber) != _peersBySerial.end()) + { + std::shared_ptr peer(std::dynamic_pointer_cast(_peersBySerial.at(serialNumber))); + return peer; + } + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return std::shared_ptr(); +} + +bool MyCentral::onPacketReceived(std::string& senderId, std::shared_ptr packet) +{ + try + { + if(_disposing) return false; + PMyPacket myPacket(std::dynamic_pointer_cast(packet)); + if(!myPacket) return false; + + PMyPeer peer = getPeer(myPacket->senderAddress()); + if(!peer) return false; + if(senderId != peer->getPhysicalInterfaceId()) return false; + + peer->packetReceived(myPacket); + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return false; +} + +void MyCentral::savePeers(bool full) +{ + try + { + std::lock_guard peersGuard(_peersMutex); + for(std::map>::iterator i = _peersById.begin(); i != _peersById.end(); ++i) + { + GD::out.printInfo("Info: Saving Intertechno peer " + std::to_string(i->second->getID())); + i->second->save(full, full, full); + } + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +void MyCentral::deletePeer(uint64_t id) +{ + try + { + std::shared_ptr peer(getPeer(id)); + if(!peer) return; + peer->deleting = true; + PVariable deviceAddresses(new Variable(VariableType::tArray)); + deviceAddresses->arrayValue->push_back(PVariable(new Variable(peer->getSerialNumber()))); + + PVariable deviceInfo(new Variable(VariableType::tStruct)); + deviceInfo->structValue->insert(StructElement("ID", PVariable(new Variable((int32_t)peer->getID())))); + PVariable channels(new Variable(VariableType::tArray)); + deviceInfo->structValue->insert(StructElement("CHANNELS", channels)); + + for(Functions::iterator i = peer->getRpcDevice()->functions.begin(); i != peer->getRpcDevice()->functions.end(); ++i) + { + deviceAddresses->arrayValue->push_back(PVariable(new Variable(peer->getSerialNumber() + ":" + std::to_string(i->first)))); + channels->arrayValue->push_back(PVariable(new Variable(i->first))); + } + + raiseRPCDeleteDevices(deviceAddresses, deviceInfo); + peer->deleteFromDatabase(); + _peersMutex.lock(); + if(_peersBySerial.find(peer->getSerialNumber()) != _peersBySerial.end()) _peersBySerial.erase(peer->getSerialNumber()); + if(_peersById.find(id) != _peersById.end()) _peersById.erase(id); + std::unordered_map>::iterator peerIterator = _peers.find(peer->getAddress()); + if(peerIterator != _peers.end() && peerIterator->second->getID() == id) _peers.erase(peerIterator); + _peersMutex.unlock(); + GD::out.printMessage("Removed Intertechno peer " + std::to_string(peer->getID())); + } + catch(const std::exception& ex) + { + _peersMutex.unlock(); + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + _peersMutex.unlock(); + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _peersMutex.unlock(); + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +std::string MyCentral::handleCliCommand(std::string command) +{ + try + { + std::ostringstream stringStream; + std::vector arguments; + bool showHelp = false; + if(_currentPeer) + { + if(BaseLib::HelperFunctions::checkCliCommand(command, "unselect", "u", "", 0, arguments, showHelp)) + { + _currentPeer.reset(); + return "Peer unselected.\n"; + } + return _currentPeer->handleCliCommand(command); + } + else if(BaseLib::HelperFunctions::checkCliCommand(command, "help", "h", "", 0, arguments, showHelp)) + { + stringStream << "List of commands:" << std::endl << std::endl; + stringStream << "For more information about the individual command type: COMMAND help" << std::endl << std::endl; + stringStream << "peers create (pc) Creates a new peer" << std::endl; + stringStream << "peers list (ls) List all peers" << std::endl; + stringStream << "peers remove (pr) Remove a peer" << std::endl; + stringStream << "peers select (ps) Select a peer" << std::endl; + stringStream << "peers setname (pn) Name a peer" << std::endl; + stringStream << "unselect (u) Unselect this device" << std::endl; + return stringStream.str(); + } + else if(BaseLib::HelperFunctions::checkCliCommand(command, "peers create", "pc", "", 3, arguments, showHelp)) + { + if(showHelp) + { + stringStream << "Description: This command creates a new peer." << std::endl; + stringStream << "Usage: peers create INTERFACE TYPE ADDRESS" << std::endl << std::endl; + stringStream << "Parameters:" << std::endl; + stringStream << " INTERFACE: The id of the interface to associate the new device to as defined in the familie's configuration file." << std::endl; + stringStream << " TYPE: The 2 byte hexadecimal device type. Example: 0xF602" << std::endl; + stringStream << " ADDRESS: The 4 byte address/ID printed on the device. Example: 0x01952B7A" << std::endl; + return stringStream.str(); + } + + std::string interfaceId = arguments.at(0); + int32_t deviceType = BaseLib::Math::getNumber(arguments.at(1), true); + if(deviceType == 0) return "Invalid device type. Device type has to be provided in hexadecimal format.\n"; + int32_t address = BaseLib::Math::getNumber(arguments.at(2), true); + std::string serial = "ITD" + BaseLib::HelperFunctions::getHexString(address, 8); + + if(peerExists(serial) || peerExists(address)) stringStream << "A peer with this address is already paired to this central." << std::endl; + else + { + std::shared_ptr peer = createPeer(deviceType, address, serial, false); + if(!peer || !peer->getRpcDevice()) return "Device type not supported.\n"; + try + { + _peersMutex.lock(); + if(!peer->getSerialNumber().empty()) _peersBySerial[peer->getSerialNumber()] = peer; + _peersMutex.unlock(); + peer->save(true, true, false); + peer->initializeCentralConfig(); + peer->setPhysicalInterfaceId(interfaceId); + _peersMutex.lock(); + _peers[peer->getAddress()] = peer; + _peersById[peer->getID()] = peer; + _peersMutex.unlock(); + } + catch(const std::exception& ex) + { + _peersMutex.unlock(); + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + _peersMutex.unlock(); + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _peersMutex.unlock(); + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + + PVariable deviceDescriptions(new Variable(VariableType::tArray)); + deviceDescriptions->arrayValue = peer->getDeviceDescriptions(nullptr, true, std::map()); + raiseRPCNewDevices(deviceDescriptions); + GD::out.printMessage("Added peer " + std::to_string(peer->getID()) + "."); + stringStream << "Added peer " << std::to_string(peer->getID()) << " with address 0x" << BaseLib::HelperFunctions::getHexString(address, 8) << " and serial number " << serial << "." << std::dec << std::endl; + } + return stringStream.str(); + } + else if(BaseLib::HelperFunctions::checkCliCommand(command, "peers remove", "pr", "", 1, arguments, showHelp)) + { + if(showHelp) + { + stringStream << "Description: This command removes a peer." << std::endl; + stringStream << "Usage: peers remove PEERID" << std::endl << std::endl; + stringStream << "Parameters:" << std::endl; + stringStream << " PEERID: The id of the peer to remove. Example: 513" << std::endl; + return stringStream.str(); + } + + uint64_t peerID = BaseLib::Math::getNumber(arguments.at(0), false); + if(peerID == 0) return "Invalid id.\n"; + + if(!peerExists(peerID)) stringStream << "This peer is not paired to this central." << std::endl; + else + { + if(_currentPeer && _currentPeer->getID() == peerID) _currentPeer.reset(); + stringStream << "Removing peer " << std::to_string(peerID) << std::endl; + deletePeer(peerID); + } + return stringStream.str(); + } + else if(BaseLib::HelperFunctions::checkCliCommand(command, "peers list", "pl", "ls", 0, arguments, showHelp)) + { + try + { + if(showHelp) + { + stringStream << "Description: This command lists information about all peers." << std::endl; + stringStream << "Usage: peers list [FILTERTYPE] [FILTERVALUE]" << std::endl << std::endl; + stringStream << "Parameters:" << std::endl; + stringStream << " FILTERTYPE: See filter types below." << std::endl; + stringStream << " FILTERVALUE: Depends on the filter type. If a number is required, it has to be in hexadecimal format." << std::endl << std::endl; + stringStream << "Filter types:" << std::endl; + stringStream << " ID: Filter by id." << std::endl; + stringStream << " FILTERVALUE: The id of the peer to filter (e. g. 513)." << std::endl; + stringStream << " SERIAL: Filter by serial number." << std::endl; + stringStream << " FILTERVALUE: The serial number of the peer to filter (e. g. JEQ0554309)." << std::endl; + stringStream << " ADDRESS: Filter by saddress." << std::endl; + stringStream << " FILTERVALUE: The address of the peer to filter (e. g. 128)." << std::endl; + stringStream << " NAME: Filter by name." << std::endl; + stringStream << " FILTERVALUE: The part of the name to search for (e. g. \"1st floor\")." << std::endl; + stringStream << " TYPE: Filter by device type." << std::endl; + stringStream << " FILTERVALUE: The 2 byte device type in hexadecimal format." << std::endl; + return stringStream.str(); + } + + std::string filterType; + std::string filterValue; + + if(arguments.size() >= 2) + { + filterType = BaseLib::HelperFunctions::toLower(arguments.at(0)); + filterValue = arguments.at(1); + if(filterType == "name") BaseLib::HelperFunctions::toLower(filterValue); + } + + if(_peersById.empty()) + { + stringStream << "No peers are paired to this central." << std::endl; + return stringStream.str(); + } + std::string bar(" │ "); + const int32_t idWidth = 8; + const int32_t nameWidth = 25; + const int32_t serialWidth = 13; + const int32_t addressWidth = 8; + const int32_t typeWidth1 = 8; + const int32_t typeWidth2 = 45; + std::string nameHeader("Name"); + nameHeader.resize(nameWidth, ' '); + std::string typeStringHeader("Type Description"); + typeStringHeader.resize(typeWidth2, ' '); + stringStream << std::setfill(' ') + << std::setw(idWidth) << "ID" << bar + << nameHeader << bar + << std::setw(serialWidth) << "Serial Number" << bar + << std::setw(addressWidth) << "Address" << bar + << std::setw(typeWidth1) << "Type" << bar + << typeStringHeader + << std::endl; + stringStream << "─────────┼───────────────────────────┼───────────────┼──────────┼──────────┼───────────────────────────────────────────────" << std::endl; + stringStream << std::setfill(' ') + << std::setw(idWidth) << " " << bar + << std::setw(nameWidth) << " " << bar + << std::setw(serialWidth) << " " << bar + << std::setw(addressWidth) << " " << bar + << std::setw(typeWidth1) << " " << bar + << std::setw(typeWidth2) + << std::endl; + _peersMutex.lock(); + for(std::map>::iterator i = _peersById.begin(); i != _peersById.end(); ++i) + { + if(filterType == "id") + { + uint64_t id = BaseLib::Math::getNumber(filterValue, false); + if(i->second->getID() != id) continue; + } + else if(filterType == "name") + { + std::string name = i->second->getName(); + if((signed)BaseLib::HelperFunctions::toLower(name).find(filterValue) == (signed)std::string::npos) continue; + } + else if(filterType == "serial") + { + if(i->second->getSerialNumber() != filterValue) continue; + } + else if(filterType == "address") + { + int32_t address = BaseLib::Math::getNumber(filterValue, true); + if(i->second->getAddress() != address) continue; + } + else if(filterType == "type") + { + int32_t deviceType = BaseLib::Math::getNumber(filterValue, true); + if((int32_t)i->second->getDeviceType() != deviceType) continue; + } + + stringStream << std::setw(idWidth) << std::setfill(' ') << std::to_string(i->second->getID()) << bar; + std::string name = i->second->getName(); + size_t nameSize = BaseLib::HelperFunctions::utf8StringSize(name); + if(nameSize > (unsigned)nameWidth) + { + name = BaseLib::HelperFunctions::utf8Substring(name, 0, nameWidth - 3); + name += "..."; + } + else name.resize(nameWidth + (name.size() - nameSize), ' '); + stringStream << name << bar + << std::setw(serialWidth) << i->second->getSerialNumber() << bar + << std::setw(addressWidth) << BaseLib::HelperFunctions::getHexString(i->second->getAddress(), 8) << bar + << std::setw(typeWidth1) << BaseLib::HelperFunctions::getHexString(i->second->getDeviceType(), 6) << bar; + if(i->second->getRpcDevice()) + { + PSupportedDevice type = i->second->getRpcDevice()->getType(i->second->getDeviceType(), i->second->getFirmwareVersion()); + std::string typeID; + if(type) typeID = type->description; + if(typeID.size() > (unsigned)typeWidth2) + { + typeID.resize(typeWidth2 - 3); + typeID += "..."; + } + else typeID.resize(typeWidth2, ' '); + stringStream << std::setw(typeWidth2) << typeID; + } + else stringStream << std::setw(typeWidth2); + stringStream << std::endl << std::dec; + } + _peersMutex.unlock(); + stringStream << "─────────┴───────────────────────────┴───────────────┴──────────┴──────────┴───────────────────────────────────────────────" << std::endl; + + return stringStream.str(); + } + catch(const std::exception& ex) + { + _peersMutex.unlock(); + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + _peersMutex.unlock(); + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _peersMutex.unlock(); + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + } + else if(command.compare(0, 13, "peers setname") == 0 || command.compare(0, 2, "pn") == 0) + { + uint64_t peerID = 0; + std::string name; + + std::stringstream stream(command); + std::string element; + int32_t offset = (command.at(1) == 'n') ? 0 : 1; + int32_t index = 0; + while(std::getline(stream, element, ' ')) + { + if(index < 1 + offset) + { + index++; + continue; + } + else if(index == 1 + offset) + { + if(element == "help") break; + else + { + peerID = BaseLib::Math::getNumber(element, false); + if(peerID == 0) return "Invalid id.\n"; + } + } + else if(index == 2 + offset) name = element; + else name += ' ' + element; + index++; + } + if(index == 1 + offset) + { + stringStream << "Description: This command sets or changes the name of a peer to identify it more easily." << std::endl; + stringStream << "Usage: peers setname PEERID NAME" << std::endl << std::endl; + stringStream << "Parameters:" << std::endl; + stringStream << " PEERID:\tThe id of the peer to set the name for. Example: 513" << std::endl; + stringStream << " NAME:\tThe name to set. Example: \"1st floor light switch\"." << std::endl; + return stringStream.str(); + } + + if(!peerExists(peerID)) stringStream << "This peer is not paired to this central." << std::endl; + else + { + std::shared_ptr peer = getPeer(peerID); + peer->setName(name); + stringStream << "Name set to \"" << name << "\"." << std::endl; + } + return stringStream.str(); + } + else if(command.compare(0, 12, "peers select") == 0 || command.compare(0, 2, "ps") == 0) + { + uint64_t id = 0; + + std::stringstream stream(command); + std::string element; + int32_t offset = (command.at(1) == 's') ? 0 : 1; + int32_t index = 0; + while(std::getline(stream, element, ' ')) + { + if(index < 1 + offset) + { + index++; + continue; + } + else if(index == 1 + offset) + { + if(element == "help") break; + id = BaseLib::Math::getNumber(element, false); + if(id == 0) return "Invalid id.\n"; + } + index++; + } + if(index == 1 + offset) + { + stringStream << "Description: This command selects a peer." << std::endl; + stringStream << "Usage: peers select PEERID" << std::endl << std::endl; + stringStream << "Parameters:" << std::endl; + stringStream << " PEERID:\tThe id of the peer to select. Example: 513" << std::endl; + return stringStream.str(); + } + + _currentPeer = getPeer(id); + if(!_currentPeer) stringStream << "This peer is not paired to this central." << std::endl; + else + { + stringStream << "Peer with id " << std::hex << std::to_string(id) << " and device type 0x" << _bl->hf.getHexString(_currentPeer->getDeviceType()) << " selected." << std::dec << std::endl; + stringStream << "For information about the peer's commands type: \"help\"" << std::endl; + } + return stringStream.str(); + } + else return "Unknown command.\n"; + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return "Error executing command. See log file for more details.\n"; +} + +std::shared_ptr MyCentral::createPeer(uint32_t deviceType, int32_t address, std::string serialNumber, bool save) +{ + try + { + std::shared_ptr peer(new MyPeer(_deviceId, this)); + peer->setDeviceType(deviceType); + peer->setAddress(address); + peer->setSerialNumber(serialNumber); + peer->setRpcDevice(GD::family->getRpcDevices()->find(deviceType, 0x10, -1)); + if(!peer->getRpcDevice()) return std::shared_ptr(); + if(save) peer->save(true, true, false); //Save and create peerID + return peer; + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return std::shared_ptr(); +} + +PVariable MyCentral::createDevice(BaseLib::PRpcClientInfo clientInfo, int32_t deviceType, std::string serialNumber, int32_t address, int32_t firmwareVersion, std::string interfaceId) +{ + try + { + std::string serial = "ITD" + BaseLib::HelperFunctions::getHexString(address, 8); + if(peerExists(serial)) return Variable::createError(-5, "This peer is already paired to this central."); + + std::shared_ptr peer = createPeer(deviceType, address, serial, false); + if(!peer || !peer->getRpcDevice()) return Variable::createError(-6, "Unknown device type."); + + try + { + peer->save(true, true, false); + peer->initializeCentralConfig(); + peer->setPhysicalInterfaceId(interfaceId); + _peersMutex.lock(); + _peers[peer->getAddress()] = peer; + _peersById[peer->getID()] = peer; + _peersBySerial[peer->getSerialNumber()] = peer; + _peersMutex.unlock(); + } + catch(const std::exception& ex) + { + _peersMutex.unlock(); + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + _peersMutex.unlock(); + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _peersMutex.unlock(); + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + + PVariable deviceDescriptions(new Variable(VariableType::tArray)); + deviceDescriptions->arrayValue = peer->getDeviceDescriptions(clientInfo, true, std::map()); + raiseRPCNewDevices(deviceDescriptions); + GD::out.printMessage("Added peer " + std::to_string(peer->getID()) + "."); + + return PVariable(new Variable((uint32_t)peer->getID())); + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return Variable::createError(-32500, "Unknown application error."); +} + +PVariable MyCentral::deleteDevice(BaseLib::PRpcClientInfo clientInfo, std::string serialNumber, int32_t flags) +{ + try + { + if(serialNumber.empty()) return Variable::createError(-2, "Unknown device."); + std::shared_ptr peer = getPeer(serialNumber); + if(!peer) return PVariable(new Variable(VariableType::tVoid)); + + return deleteDevice(clientInfo, peer->getID(), flags); + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return Variable::createError(-32500, "Unknown application error."); +} + +PVariable MyCentral::deleteDevice(BaseLib::PRpcClientInfo clientInfo, uint64_t peerID, int32_t flags) +{ + try + { + if(peerID == 0) return Variable::createError(-2, "Unknown device."); + std::shared_ptr peer = getPeer(peerID); + if(!peer) return PVariable(new Variable(VariableType::tVoid)); + uint64_t id = peer->getID(); + + deletePeer(id); + + if(peerExists(id)) return Variable::createError(-1, "Error deleting peer. See log for more details."); + + return PVariable(new Variable(VariableType::tVoid)); + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return Variable::createError(-32500, "Unknown application error."); +} + +PVariable MyCentral::getDeviceInfo(BaseLib::PRpcClientInfo clientInfo, uint64_t id, std::map fields) +{ + try + { + if(id > 0) + { + std::shared_ptr peer(getPeer(id)); + if(!peer) return Variable::createError(-2, "Unknown device."); + + return peer->getDeviceInfo(clientInfo, fields); + } + else + { + PVariable array(new Variable(VariableType::tArray)); + + std::vector> peers; + //Copy all peers first, because listDevices takes very long and we don't want to lock _peersMutex too long + _peersMutex.lock(); + for(std::map>::iterator i = _peersById.begin(); i != _peersById.end(); ++i) + { + peers.push_back(std::dynamic_pointer_cast(i->second)); + } + _peersMutex.unlock(); + + for(std::vector>::iterator i = peers.begin(); i != peers.end(); ++i) + { + //listDevices really needs a lot of resources, so wait a little bit after each device + std::this_thread::sleep_for(std::chrono::milliseconds(3)); + PVariable info = (*i)->getDeviceInfo(clientInfo, fields); + if(!info) continue; + array->arrayValue->push_back(info); + } + + return array; + } + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return Variable::createError(-32500, "Unknown application error."); +} + +PVariable MyCentral::putParamset(BaseLib::PRpcClientInfo clientInfo, std::string serialNumber, int32_t channel, ParameterGroup::Type::Enum type, std::string remoteSerialNumber, int32_t remoteChannel, PVariable paramset) +{ + try + { + std::shared_ptr peer(getPeer(serialNumber)); + uint64_t remoteID = 0; + if(!remoteSerialNumber.empty()) + { + std::shared_ptr remotePeer(getPeer(remoteSerialNumber)); + if(!remotePeer) return Variable::createError(-3, "Remote peer is unknown."); + remoteID = remotePeer->getID(); + } + if(peer) return peer->putParamset(clientInfo, channel, type, remoteID, remoteChannel, paramset); + return Variable::createError(-2, "Unknown device."); + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return Variable::createError(-32500, "Unknown application error."); +} + +PVariable MyCentral::putParamset(BaseLib::PRpcClientInfo clientInfo, uint64_t peerID, int32_t channel, ParameterGroup::Type::Enum type, uint64_t remoteID, int32_t remoteChannel, PVariable paramset) +{ + try + { + std::shared_ptr peer(getPeer(peerID)); + if(peer) return peer->putParamset(clientInfo, channel, type, remoteID, remoteChannel, paramset); + return Variable::createError(-2, "Unknown device."); + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return Variable::createError(-32500, "Unknown application error."); +} + +PVariable MyCentral::setInterface(BaseLib::PRpcClientInfo clientInfo, uint64_t peerId, std::string interfaceId) +{ + try + { + std::shared_ptr peer(getPeer(peerId)); + if(!peer) return Variable::createError(-2, "Unknown device."); + return peer->setInterface(clientInfo, interfaceId); + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return Variable::createError(-32500, "Unknown application error."); +} + +} diff --git a/src/MyCentral.h b/src/MyCentral.h new file mode 100644 index 0000000..b0de51a --- /dev/null +++ b/src/MyCentral.h @@ -0,0 +1,78 @@ +/* Copyright 2013-2016 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 MYCENTRAL_H_ +#define MYCENTRAL_H_ + +#include "MyPeer.h" +#include "MyPacket.h" +#include + +#include +#include +#include + +namespace MyFamily +{ + +class MyCentral : public BaseLib::Systems::ICentral +{ +public: + MyCentral(ICentralEventSink* eventHandler); + MyCentral(uint32_t deviceType, std::string serialNumber, ICentralEventSink* eventHandler); + virtual ~MyCentral(); + virtual void dispose(bool wait = true); + + std::string handleCliCommand(std::string command); + virtual bool onPacketReceived(std::string& senderId, std::shared_ptr packet); + + std::shared_ptr getPeer(uint64_t id); + std::shared_ptr getPeer(int32_t address); + std::shared_ptr getPeer(std::string serialNumber); + + virtual PVariable createDevice(BaseLib::PRpcClientInfo clientInfo, int32_t deviceType, std::string serialNumber, int32_t address, int32_t firmwareVersion, std::string interfaceId); + virtual PVariable deleteDevice(BaseLib::PRpcClientInfo clientInfo, std::string serialNumber, int32_t flags); + virtual PVariable deleteDevice(BaseLib::PRpcClientInfo clientInfo, uint64_t peerId, int32_t flags); + virtual PVariable getDeviceInfo(BaseLib::PRpcClientInfo clientInfo, uint64_t id, std::map fields); + virtual PVariable putParamset(BaseLib::PRpcClientInfo clientInfo, std::string serialNumber, int32_t channel, ParameterGroup::Type::Enum type, std::string remoteSerialNumber, int32_t remoteChannel, PVariable paramset); + virtual PVariable putParamset(BaseLib::PRpcClientInfo clientInfo, uint64_t peerId, int32_t channel, ParameterGroup::Type::Enum type, uint64_t remoteId, int32_t remoteChannel, PVariable paramset); + virtual PVariable setInterface(BaseLib::PRpcClientInfo clientInfo, uint64_t peerId, std::string interfaceId); +protected: + virtual void init(); + virtual void loadPeers(); + virtual void savePeers(bool full); + virtual void loadVariables() {} + virtual void saveVariables() {} + std::shared_ptr createPeer(uint32_t deviceType, int32_t address, std::string serialNumber, bool save = true); + void deletePeer(uint64_t id); +}; + +} + +#endif diff --git a/src/MyFamily.cpp b/src/MyFamily.cpp new file mode 100644 index 0000000..66f0771 --- /dev/null +++ b/src/MyFamily.cpp @@ -0,0 +1,110 @@ +/* Copyright 2013-2016 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 "GD.h" +#include "Interfaces.h" +#include "MyFamily.h" +#include "MyCentral.h" + +namespace MyFamily +{ + +MyFamily::MyFamily(BaseLib::Obj* bl, BaseLib::Systems::DeviceFamily::IFamilyEventSink* eventHandler) : BaseLib::Systems::DeviceFamily(bl, eventHandler, MY_FAMILY_ID, MY_FAMILY_NAME) +{ + GD::bl = bl; + GD::family = this; + GD::out.init(bl); + GD::out.setPrefix(std::string("Module ") + MY_FAMILY_NAME + ": "); + GD::out.printDebug("Debug: Loading module..."); + _physicalInterfaces.reset(new Interfaces(bl, _settings->getPhysicalInterfaceSettings())); +} + +MyFamily::~MyFamily() +{ + +} + +void MyFamily::dispose() +{ + if(_disposed) return; + DeviceFamily::dispose(); + + _central.reset(); +} + +void MyFamily::createCentral() +{ + try + { + _central.reset(new MyCentral(0, "VIT0000001", this)); + GD::out.printMessage("Created central with id " + std::to_string(_central->getId()) + "."); + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +std::shared_ptr MyFamily::initializeCentral(uint32_t deviceId, int32_t address, std::string serialNumber) +{ + return std::shared_ptr(new MyCentral(deviceId, serialNumber, this)); +} + +PVariable MyFamily::getPairingMethods() +{ + try + { + if(!_central) return PVariable(new Variable(VariableType::tArray)); + PVariable array(new Variable(VariableType::tArray)); + array->arrayValue->push_back(PVariable(new Variable(std::string("createDevice")))); + return array; + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return Variable::createError(-32500, "Unknown application error."); +} +} diff --git a/src/MyFamily.h b/src/MyFamily.h new file mode 100644 index 0000000..653a5cd --- /dev/null +++ b/src/MyFamily.h @@ -0,0 +1,57 @@ +/* Copyright 2013-2016 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 MYFAMILY_H_ +#define MYFAMILY_H_ + +#include + +using namespace BaseLib; + +namespace MyFamily +{ +class MyCentral; + +class MyFamily : public BaseLib::Systems::DeviceFamily +{ +public: + MyFamily(BaseLib::Obj* bl, BaseLib::Systems::DeviceFamily::IFamilyEventSink* eventHandler); + virtual ~MyFamily(); + virtual void dispose(); + + virtual bool hasPhysicalInterface() { return true; } + virtual PVariable getPairingMethods(); +protected: + virtual std::shared_ptr initializeCentral(uint32_t deviceId, int32_t address, std::string serialNumber); + virtual void createCentral(); +}; + +} + +#endif diff --git a/src/MyPacket.cpp b/src/MyPacket.cpp new file mode 100644 index 0000000..7a4f847 --- /dev/null +++ b/src/MyPacket.cpp @@ -0,0 +1,94 @@ +/* Copyright 2013-2016 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 "MyPacket.h" + +#include "GD.h" + +namespace MyFamily +{ +MyPacket::MyPacket() +{ +} + +MyPacket::MyPacket(int32_t senderAddress, std::string& payload) : _payload(payload) +{ + _senderAddress = senderAddress; +} + +MyPacket::~MyPacket() +{ + _payload.clear(); +} + +std::string MyPacket::hexString() +{ + try + { + if(!_packet.empty()) return _packet; + if(_senderAddress & 0xFFFFFC00) + { + std::cerr << "Moin" << std::hex << _senderAddress << std::dec << std::endl; + _packet.reserve(32); + for(int32_t i = 29; i >= 4; i--) + { + _packet.push_back(_senderAddress & (1 << i) ? '1' : '0'); + } + _packet.insert(_packet.end(), _payload.begin(), _payload.end()); + for(int32_t i = 3; i >= 0; i--) + { + _packet.push_back(_senderAddress & (1 << i) ? '1' : '0'); + } + } + else + { + _packet.reserve(12); + for(int32_t i = 9; i >= 0; i--) + { + _packet.push_back(_senderAddress & (1 << i) ? '1' : '0'); + } + _packet.insert(_packet.end(), _payload.begin(), _payload.end()); + } + return _packet; + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return ""; +} +} diff --git a/src/MyPacket.h b/src/MyPacket.h new file mode 100644 index 0000000..abcd6ac --- /dev/null +++ b/src/MyPacket.h @@ -0,0 +1,54 @@ +/* Copyright 2013-2016 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 MYPACKET_H_ +#define MYPACKET_H_ + +#include + +namespace MyFamily +{ + +class MyPacket : public BaseLib::Systems::Packet +{ + public: + MyPacket(); + MyPacket(int32_t senderAddress, std::string& payload); + virtual ~MyPacket(); + + std::string hexString(); + protected: + std::string _packet; + std::string _payload; +}; + +typedef std::shared_ptr PMyPacket; + +} +#endif diff --git a/src/MyPeer.cpp b/src/MyPeer.cpp new file mode 100644 index 0000000..6e57b36 --- /dev/null +++ b/src/MyPeer.cpp @@ -0,0 +1,704 @@ +/* Copyright 2013-2016 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 "MyPeer.h" + +#include "GD.h" +#include "MyPacket.h" +#include "MyCentral.h" + +namespace MyFamily +{ +std::shared_ptr MyPeer::getCentral() +{ + try + { + if(_central) return _central; + _central = GD::family->getCentral(); + return _central; + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return std::shared_ptr(); +} + +MyPeer::MyPeer(uint32_t parentID, IPeerEventSink* eventHandler) : BaseLib::Systems::Peer(GD::bl, parentID, eventHandler) +{ + init(); +} + +MyPeer::MyPeer(int32_t id, int32_t address, std::string serialNumber, uint32_t parentID, IPeerEventSink* eventHandler) : BaseLib::Systems::Peer(GD::bl, id, address, serialNumber, parentID, eventHandler) +{ + init(); +} + +MyPeer::~MyPeer() +{ + try + { + dispose(); + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +void MyPeer::init() +{ + try + { + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +void MyPeer::dispose() +{ + if(_disposing) return; + Peer::dispose(); +} + +void MyPeer::homegearStarted() +{ + try + { + Peer::homegearStarted(); + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +void MyPeer::homegearShuttingDown() +{ + try + { + _shuttingDown = true; + Peer::homegearShuttingDown(); + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +std::string MyPeer::handleCliCommand(std::string command) +{ + try + { + std::ostringstream stringStream; + + if(command == "help") + { + stringStream << "List of commands:" << std::endl << std::endl; + stringStream << "For more information about the individual command type: COMMAND help" << std::endl << std::endl; + stringStream << "unselect\t\tUnselect this peer" << std::endl; + stringStream << "channel count\t\tPrint the number of channels of this peer" << std::endl; + stringStream << "config print\t\tPrints all configuration parameters and their values" << std::endl; + return stringStream.str(); + } + if(command.compare(0, 13, "channel count") == 0) + { + std::stringstream stream(command); + std::string element; + int32_t index = 0; + while(std::getline(stream, element, ' ')) + { + if(index < 2) + { + index++; + continue; + } + else if(index == 2) + { + if(element == "help") + { + stringStream << "Description: This command prints this peer's number of channels." << std::endl; + stringStream << "Usage: channel count" << std::endl << std::endl; + stringStream << "Parameters:" << std::endl; + stringStream << " There are no parameters." << std::endl; + return stringStream.str(); + } + } + index++; + } + + stringStream << "Peer has " << _rpcDevice->functions.size() << " channels." << std::endl; + return stringStream.str(); + } + else if(command.compare(0, 12, "config print") == 0) + { + std::stringstream stream(command); + std::string element; + int32_t index = 0; + while(std::getline(stream, element, ' ')) + { + if(index < 2) + { + index++; + continue; + } + else if(index == 2) + { + if(element == "help") + { + stringStream << "Description: This command prints all configuration parameters of this peer. The values are in BidCoS packet format." << std::endl; + stringStream << "Usage: config print" << std::endl << std::endl; + stringStream << "Parameters:" << std::endl; + stringStream << " There are no parameters." << std::endl; + return stringStream.str(); + } + } + index++; + } + + return printConfig(); + } + else return "Unknown command.\n"; + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return "Error executing command. See log file for more details.\n"; +} + +std::string MyPeer::printConfig() +{ + try + { + std::ostringstream stringStream; + stringStream << "MASTER" << std::endl; + stringStream << "{" << std::endl; + for(std::unordered_map>::const_iterator i = configCentral.begin(); i != configCentral.end(); ++i) + { + stringStream << "\t" << "Channel: " << std::dec << i->first << std::endl; + stringStream << "\t{" << std::endl; + for(std::unordered_map::const_iterator j = i->second.begin(); j != i->second.end(); ++j) + { + stringStream << "\t\t[" << j->first << "]: "; + if(!j->second.rpcParameter) stringStream << "(No RPC parameter) "; + for(std::vector::const_iterator k = j->second.data.begin(); k != j->second.data.end(); ++k) + { + stringStream << std::hex << std::setfill('0') << std::setw(2) << (int32_t)*k << " "; + } + stringStream << std::endl; + } + stringStream << "\t}" << std::endl; + } + stringStream << "}" << std::endl << std::endl; + + stringStream << "VALUES" << std::endl; + stringStream << "{" << std::endl; + for(std::unordered_map>::const_iterator i = valuesCentral.begin(); i != valuesCentral.end(); ++i) + { + stringStream << "\t" << "Channel: " << std::dec << i->first << std::endl; + stringStream << "\t{" << std::endl; + for(std::unordered_map::const_iterator j = i->second.begin(); j != i->second.end(); ++j) + { + stringStream << "\t\t[" << j->first << "]: "; + if(!j->second.rpcParameter) stringStream << "(No RPC parameter) "; + for(std::vector::const_iterator k = j->second.data.begin(); k != j->second.data.end(); ++k) + { + stringStream << std::hex << std::setfill('0') << std::setw(2) << (int32_t)*k << " "; + } + stringStream << std::endl; + } + stringStream << "\t}" << std::endl; + } + stringStream << "}" << std::endl << std::endl; + + return stringStream.str(); + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return ""; +} + +void MyPeer::setPhysicalInterfaceId(std::string id) +{ + if(id.empty() || (GD::physicalInterfaces.find(id) != GD::physicalInterfaces.end() && GD::physicalInterfaces.at(id))) + { + _physicalInterfaceId = id; + setPhysicalInterface(id.empty() ? GD::defaultPhysicalInterface : GD::physicalInterfaces.at(_physicalInterfaceId)); + saveVariable(19, _physicalInterfaceId); + } +} + +void MyPeer::setPhysicalInterface(std::shared_ptr interface) +{ + try + { + if(!interface) return; + _physicalInterface = interface; + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +void MyPeer::loadVariables(BaseLib::Systems::ICentral* central, std::shared_ptr& rows) +{ + try + { + if(!rows) rows = _bl->db->getPeerVariables(_peerID); + Peer::loadVariables(central, rows); + + _rpcDevice = GD::family->getRpcDevices()->find(_deviceType, _firmwareVersion, -1); + if(!_rpcDevice) return; + + for(BaseLib::Database::DataTable::iterator row = rows->begin(); row != rows->end(); ++row) + { + switch(row->second.at(2)->intValue) + { + case 19: + _physicalInterfaceId = row->second.at(4)->textValue; + if(!_physicalInterfaceId.empty() && GD::physicalInterfaces.find(_physicalInterfaceId) != GD::physicalInterfaces.end()) setPhysicalInterface(GD::physicalInterfaces.at(_physicalInterfaceId)); + break; + } + } + if(!_physicalInterface) _physicalInterface = GD::defaultPhysicalInterface; + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +void MyPeer::saveVariables() +{ + try + { + if(_peerID == 0) return; + Peer::saveVariables(); + saveVariable(19, _physicalInterfaceId); + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +bool MyPeer::load(BaseLib::Systems::ICentral* central) +{ + try + { + std::shared_ptr rows; + loadVariables(central, rows); + if(!_rpcDevice) + { + GD::out.printError("Error loading peer " + std::to_string(_peerID) + ": Device type not found: 0x" + BaseLib::HelperFunctions::getHexString(_deviceType) + " Firmware version: " + std::to_string(_firmwareVersion)); + return false; + } + + initializeTypeString(); + std::string entry; + loadConfig(); + initializeCentralConfig(); + + serviceMessages.reset(new BaseLib::Systems::ServiceMessages(_bl, _peerID, _serialNumber, this)); + serviceMessages->load(); + + std::unordered_map>::iterator channelIterator = configCentral.find(0); + if(channelIterator != configCentral.end()) + { + std::unordered_map::iterator parameterIterator = channelIterator->second.find("ADDRESS"); + if(parameterIterator != channelIterator->second.end() && parameterIterator->second.rpcParameter) + { + _address = parameterIterator->second.rpcParameter->convertFromPacket(parameterIterator->second.data)->booleanValue; + } + } + + return true; + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return false; +} + +void MyPeer::packetReceived(PMyPacket& packet) +{ +} + +PParameterGroup MyPeer::getParameterSet(int32_t channel, ParameterGroup::Type::Enum type) +{ + try + { + PFunction rpcChannel = _rpcDevice->functions.at(channel); + if(type == ParameterGroup::Type::Enum::variables) return rpcChannel->variables; + else if(type == ParameterGroup::Type::Enum::config) return rpcChannel->configParameters; + else if(type == ParameterGroup::Type::Enum::link) return rpcChannel->linkParameters; + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return PParameterGroup(); +} + +bool MyPeer::getAllValuesHook2(PRpcClientInfo clientInfo, PParameter parameter, uint32_t channel, PVariable parameters) +{ + try + { + if(channel == 1) + { + if(parameter->id == "PEER_ID") parameter->convertToPacket(PVariable(new Variable((int32_t)_peerID)), valuesCentral[channel][parameter->id].data); + } + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return false; +} + +bool MyPeer::getParamsetHook2(PRpcClientInfo clientInfo, PParameter parameter, uint32_t channel, PVariable parameters) +{ + try + { + if(channel == 1) + { + if(parameter->id == "PEER_ID") parameter->convertToPacket(PVariable(new Variable((int32_t)_peerID)), valuesCentral[channel][parameter->id].data); + } + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return false; +} + +PVariable MyPeer::putParamset(BaseLib::PRpcClientInfo clientInfo, int32_t channel, ParameterGroup::Type::Enum type, uint64_t remoteID, int32_t remoteChannel, PVariable variables, bool onlyPushing) +{ + try + { + if(_disposing) return Variable::createError(-32500, "Peer is disposing."); + if(channel < 0) channel = 0; + if(remoteChannel < 0) remoteChannel = 0; + Functions::iterator functionIterator = _rpcDevice->functions.find(channel); + if(functionIterator == _rpcDevice->functions.end()) return Variable::createError(-2, "Unknown channel."); + if(type == ParameterGroup::Type::none) type = ParameterGroup::Type::link; + PParameterGroup parameterGroup = functionIterator->second->getParameterGroup(type); + if(!parameterGroup) return Variable::createError(-3, "Unknown parameter set."); + if(variables->structValue->empty()) return PVariable(new Variable(VariableType::tVoid)); + + if(type == ParameterGroup::Type::Enum::config) + { + bool parameterChanged = false; + for(Struct::iterator i = variables->structValue->begin(); i != variables->structValue->end(); ++i) + { + if(i->first.empty() || !i->second) continue; + if(configCentral[channel].find(i->first) == configCentral[channel].end()) continue; + BaseLib::Systems::RPCConfigurationParameter& parameter = configCentral[channel][i->first]; + if(!parameter.rpcParameter) continue; + if(parameter.rpcParameter->password && i->second->stringValue.empty()) continue; //Don't safe password if empty + parameter.rpcParameter->convertToPacket(i->second, parameter.data); + if(parameter.databaseID > 0) saveParameter(parameter.databaseID, parameter.data); + else saveParameter(0, ParameterGroup::Type::Enum::config, channel, i->first, parameter.data); + + parameterChanged = true; + GD::out.printInfo("Info: Parameter " + i->first + " of peer " + std::to_string(_peerID) + " and channel " + std::to_string(channel) + " was set to 0x" + BaseLib::HelperFunctions::getHexString(parameter.data) + "."); + } + + if(parameterChanged) raiseRPCUpdateDevice(_peerID, channel, _serialNumber + ":" + std::to_string(channel), 0); + } + else if(type == ParameterGroup::Type::Enum::variables) + { + for(Struct::iterator i = variables->structValue->begin(); i != variables->structValue->end(); ++i) + { + if(i->first.empty() || !i->second) continue; + setValue(clientInfo, channel, i->first, i->second, false); + } + } + else + { + return Variable::createError(-3, "Parameter set type is not supported."); + } + return PVariable(new Variable(VariableType::tVoid)); + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return Variable::createError(-32500, "Unknown application error."); +} + +PVariable MyPeer::setInterface(BaseLib::PRpcClientInfo clientInfo, std::string interfaceId) +{ + try + { + if(!interfaceId.empty() && GD::physicalInterfaces.find(interfaceId) == GD::physicalInterfaces.end()) + { + return Variable::createError(-5, "Unknown physical interface."); + } + std::shared_ptr interface(GD::physicalInterfaces.at(interfaceId)); + setPhysicalInterfaceId(interfaceId); + return PVariable(new Variable(VariableType::tVoid)); + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return Variable::createError(-32500, "Unknown application error."); +} + +PVariable MyPeer::setValue(BaseLib::PRpcClientInfo clientInfo, uint32_t channel, std::string valueKey, PVariable value, bool wait) +{ + try + { + Peer::setValue(clientInfo, channel, valueKey, value, wait); //Ignore result, otherwise setHomegerValue might not be executed + if(_disposing) return Variable::createError(-32500, "Peer is disposing."); + std::shared_ptr central = std::dynamic_pointer_cast(getCentral()); + if(!central) return Variable::createError(-32500, "Could not get central object.");; + if(valueKey.empty()) return Variable::createError(-5, "Value key is empty."); + if(channel == 0 && serviceMessages->set(valueKey, value->booleanValue)) return PVariable(new Variable(VariableType::tVoid)); + std::unordered_map>::iterator channelIterator = valuesCentral.find(channel); + if(channelIterator == valuesCentral.end()) return Variable::createError(-2, "Unknown channel."); + std::unordered_map::iterator parameterIterator = channelIterator->second.find(valueKey); + if(parameterIterator == valuesCentral[channel].end()) return Variable::createError(-5, "Unknown parameter."); + PParameter rpcParameter = parameterIterator->second.rpcParameter; + if(!rpcParameter) return Variable::createError(-5, "Unknown parameter."); + BaseLib::Systems::RPCConfigurationParameter& parameter = valuesCentral[channel][valueKey]; + std::shared_ptr> valueKeys(new std::vector()); + std::shared_ptr> values(new std::vector()); + if(rpcParameter->readable) + { + valueKeys->push_back(valueKey); + values->push_back(value); + } + if(rpcParameter->physical->operationType == IPhysical::OperationType::Enum::store) + { + rpcParameter->convertToPacket(value, parameter.data); + if(parameter.databaseID > 0) saveParameter(parameter.databaseID, parameter.data); + else saveParameter(0, ParameterGroup::Type::Enum::variables, channel, valueKey, parameter.data); + if(!valueKeys->empty()) + { + raiseEvent(_peerID, channel, valueKeys, values); + raiseRPCEvent(_peerID, channel, _serialNumber + ":" + std::to_string(channel), valueKeys, values); + } + return PVariable(new Variable(VariableType::tVoid)); + } + else if(rpcParameter->physical->operationType != IPhysical::OperationType::Enum::command) return Variable::createError(-6, "Parameter is not settable."); + + rpcParameter->convertToPacket(value, parameter.data); + if(parameter.databaseID > 0) saveParameter(parameter.databaseID, parameter.data); + else saveParameter(0, ParameterGroup::Type::Enum::variables, channel, valueKey, parameter.data); + if(_bl->debugLevel >= 4) GD::out.printInfo("Info: " + valueKey + " of peer " + std::to_string(_peerID) + " with serial number " + _serialNumber + ":" + std::to_string(channel) + " was set to 0x" + BaseLib::HelperFunctions::getHexString(parameter.data) + "."); + + PMyPacket packet; + if(valueKey == "STATE") + { + std::string payload; + if(value->booleanValue) payload = (_address & 0xFFFFFC00) ? "01" : "FF"; + else payload = (_address & 0xFFFFFC00) ? "00" : "F0"; + packet.reset(new MyPacket(_address, payload)); + } + if(valueKey == "GROUP_STATE") + { + std::string payload; + if(value->booleanValue) payload = (_address & 0xFFFFFC00) ? "11" : "FF"; + else payload = (_address & 0xFFFFFC00) ? "10" : "F0"; + packet.reset(new MyPacket(_address, payload)); + } + else if(valueKey == "PAIRING") + { + std::string payload = (_address & 0xFFFFFC00) ? "01" : "FF"; + packet.reset(new MyPacket(_address, payload)); + } + else if(valueKey == "UNPAIRING") + { + std::string payload = (_address & 0xFFFFFC00) ? "00" : "F0"; + packet.reset(new MyPacket(_address, payload)); + } + + if(packet) _physicalInterface->sendPacket(packet); + + if(!valueKeys->empty()) + { + raiseEvent(_peerID, channel, valueKeys, values); + raiseRPCEvent(_peerID, channel, _serialNumber + ":" + std::to_string(channel), valueKeys, values); + } + + return PVariable(new Variable(VariableType::tVoid)); + } + catch(const std::exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } + return Variable::createError(-32500, "Unknown application error. See error log for more details."); +} + +} diff --git a/src/MyPeer.h b/src/MyPeer.h new file mode 100644 index 0000000..e14e6bc --- /dev/null +++ b/src/MyPeer.h @@ -0,0 +1,126 @@ +/* Copyright 2013-2016 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 MYPEER_H_ +#define MYPEER_H_ + +#include "MyPacket.h" +#include +#include "PhysicalInterfaces/IIntertechnoInterface.h" + +using namespace BaseLib; +using namespace BaseLib::DeviceDescription; + +namespace MyFamily +{ +class MyCentral; + +class MyPeer : public BaseLib::Systems::Peer, public BaseLib::Rpc::IWebserverEventSink +{ +public: + MyPeer(uint32_t parentID, IPeerEventSink* eventHandler); + MyPeer(int32_t id, int32_t address, std::string serialNumber, uint32_t parentID, IPeerEventSink* eventHandler); + virtual ~MyPeer(); + void init(); + void dispose(); + + //Features + virtual bool wireless() { return true; } + //End features + + //{{{ In table variables + std::string getPhysicalInterfaceId() { return _physicalInterfaceId; } + void setPhysicalInterfaceId(std::string); + //}}} + + std::shared_ptr& getPhysicalInterface() { return _physicalInterface; } + + virtual std::string handleCliCommand(std::string command); + void packetReceived(PMyPacket& packet); + + virtual bool load(BaseLib::Systems::ICentral* central); + virtual void savePeers() {} + + virtual int32_t getChannelGroupedWith(int32_t channel) { return -1; } + virtual int32_t getNewFirmwareVersion() { return 0; } + virtual std::string getFirmwareVersionString(int32_t firmwareVersion) { return "1.0"; } + virtual bool firmwareUpdateAvailable() { return false; } + + std::string printConfig(); + + /** + * {@inheritDoc} + */ + virtual void homegearStarted(); + + /** + * {@inheritDoc} + */ + virtual void homegearShuttingDown(); + + //RPC methods + virtual PVariable putParamset(BaseLib::PRpcClientInfo clientInfo, int32_t channel, ParameterGroup::Type::Enum type, uint64_t remoteID, int32_t remoteChannel, PVariable variables, bool onlyPushing = false); + PVariable setInterface(BaseLib::PRpcClientInfo clientInfo, std::string interfaceId); + virtual PVariable setValue(BaseLib::PRpcClientInfo clientInfo, uint32_t channel, std::string valueKey, PVariable value, bool wait); + //End RPC methods +protected: + //In table variables: + std::string _physicalInterfaceId; + //End + + bool _shuttingDown = false; + std::shared_ptr _physicalInterface; + + virtual void loadVariables(BaseLib::Systems::ICentral* central, std::shared_ptr& rows); + virtual void saveVariables(); + + virtual void setPhysicalInterface(std::shared_ptr interface); + + virtual std::shared_ptr getCentral(); + + virtual PParameterGroup getParameterSet(int32_t channel, ParameterGroup::Type::Enum type); + + // {{{ Hooks + /** + * {@inheritDoc} + */ + virtual bool getAllValuesHook2(PRpcClientInfo clientInfo, PParameter parameter, uint32_t channel, PVariable parameters); + + /** + * {@inheritDoc} + */ + virtual bool getParamsetHook2(PRpcClientInfo clientInfo, PParameter parameter, uint32_t channel, PVariable parameters); + // }}} +}; + +typedef std::shared_ptr PMyPeer; + +} + +#endif diff --git a/src/PhysicalInterfaces/Cul.cpp b/src/PhysicalInterfaces/Cul.cpp new file mode 100644 index 0000000..97f7394 --- /dev/null +++ b/src/PhysicalInterfaces/Cul.cpp @@ -0,0 +1,158 @@ +/* Copyright 2013-2016 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 "../GD.h" +#include "Cul.h" + +namespace MyFamily +{ + +Cul::Cul(std::shared_ptr settings) : IIntertechnoInterface(settings) +{ + _settings = settings; + _out.init(GD::bl); + _out.setPrefix(GD::out.getPrefix() + "Intertechno CUL \"" + settings->id + "\": "); + + signal(SIGPIPE, SIG_IGN); +} + +Cul::~Cul() +{ + stopListening(); +} + +void Cul::startListening() +{ + try + { + stopListening(); + + if(_settings->device.empty()) + { + _out.printError("Error: No device defined for CUL. Please specify it in \"intertechno.conf\"."); + return; + } + + _serial.reset(new BaseLib::SerialReaderWriter(_bl, _settings->device, 57600, 0, true, -1)); + _serial->openDevice(false, false, false); + if(!_serial->isOpen()) + { + _out.printError("Error: Could not open device."); + return; + } + + _stopCallbackThread = false; + _stopped = false; + IPhysicalInterface::startListening(); + } + catch(const std::exception& ex) + { + _out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + _out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +void Cul::stopListening() +{ + try + { + _stopCallbackThread = true; + _bl->threadManager.join(_listenThread); + _stopped = true; + if(_serial) _serial->closeDevice(); + IPhysicalInterface::stopListening(); + } + catch(const std::exception& ex) + { + _out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + _out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +void Cul::sendPacket(std::shared_ptr packet) +{ + try + { + std::shared_ptr myPacket(std::dynamic_pointer_cast(packet)); + if(!myPacket) return; + + if(_stopped || !_serial) + { + _out.printWarning("Warning: !!!Not!!! sending packet " + myPacket->hexString() + ", because device is not open."); + return; + } + + if(!_serial->isOpen()) + { + _serial->closeDevice(); + _serial->openDevice(false, false, false); + if(!_serial->isOpen()) + { + _out.printError("Error: Could not open device."); + return; + } + } + + std::string hexString = "is" + myPacket->hexString() + "\n"; + std::vector data; + data.insert(data.end(), hexString.begin(), hexString.end()); + + _out.printInfo("Info: Sending (" + _settings->id + "): " + packet->hexString()); + + _serial->writeData(data); + } + catch(const std::exception& ex) + { + _out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(BaseLib::Exception& ex) + { + _out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); + } + catch(...) + { + _out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); + } +} + +} diff --git a/src/PhysicalInterfaces/Cul.h b/src/PhysicalInterfaces/Cul.h new file mode 100644 index 0000000..d8cf133 --- /dev/null +++ b/src/PhysicalInterfaces/Cul.h @@ -0,0 +1,58 @@ +/* Copyright 2013-2016 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 CUL_H_ +#define CUL_H_ + +#include "../MyPacket.h" +#include +#include "IIntertechnoInterface.h" + +namespace MyFamily +{ + +class Cul : public IIntertechnoInterface +{ +public: + Cul(std::shared_ptr settings); + virtual ~Cul(); + + virtual void startListening(); + virtual void stopListening(); + + virtual bool isOpen() { return _serial && _serial->isOpen() && !_stopped; } + + virtual void sendPacket(std::shared_ptr packet); +protected: + std::unique_ptr _serial; +}; + +} + +#endif diff --git a/src/PhysicalInterfaces/IIntertechnoInterface.cpp b/src/PhysicalInterfaces/IIntertechnoInterface.cpp new file mode 100644 index 0000000..0b6ae55 --- /dev/null +++ b/src/PhysicalInterfaces/IIntertechnoInterface.cpp @@ -0,0 +1,54 @@ +/* Copyright 2013-2016 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 "../GD.h" +#include "../MyPacket.h" +#include "IIntertechnoInterface.h" + +namespace MyFamily +{ + +IIntertechnoInterface::IIntertechnoInterface(std::shared_ptr settings) : IPhysicalInterface(GD::bl, GD::family->getFamily(), settings) +{ + _bl = GD::bl; + + if(settings->listenThreadPriority == -1) + { + settings->listenThreadPriority = 0; + settings->listenThreadPolicy = SCHED_OTHER; + } +} + +IIntertechnoInterface::~IIntertechnoInterface() +{ + +} + + +} diff --git a/src/PhysicalInterfaces/IIntertechnoInterface.h b/src/PhysicalInterfaces/IIntertechnoInterface.h new file mode 100644 index 0000000..b5f6775 --- /dev/null +++ b/src/PhysicalInterfaces/IIntertechnoInterface.h @@ -0,0 +1,55 @@ +/* Copyright 2013-2016 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 IINTERTECHNOINTERFACE_H_ +#define IINTERTECHNOINTERFACE_H_ + +#include + +namespace MyFamily +{ + +class IIntertechnoInterface : public BaseLib::Systems::IPhysicalInterface +{ +public: + IIntertechnoInterface(std::shared_ptr settings); + virtual ~IIntertechnoInterface(); + + virtual void startListening() {} + virtual void stopListening() {} + + virtual void sendPacket(std::shared_ptr packet) {} +protected: + BaseLib::Obj* _bl = nullptr; + BaseLib::Output _out; +}; + +} + +#endif