diff --git a/Gopkg.lock b/Gopkg.lock index 8a9d00328..364d82bf5 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -471,11 +471,11 @@ [[projects]] branch = "master" - digest = "1:7f8209ffee3634c5a24ce6993bd0385584f4bb159db733b07289ca1d86ed0313" + digest = "1:9f15b02d916da48250632663a73015caeec06c284bb0e44e9f31c561f01b8d96" name = "github.com/t-tiger/gorm-bulk-insert" packages = ["."] pruneopts = "UT" - revision = "d028f1d13a79cf51420e00710c61ed21d9a22ad5" + revision = "ec69ce854cfe0a6f8975cecbe5d1d978b2d8d108" [[projects]] digest = "1:420817f94b6c172dabb8a054d0b2d257d7437a87c7c8c7ee432bc008a577fc46" diff --git a/README.md b/README.md index 6f8a34936..0dfcff72e 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ services. The basic principles underlying the system being developed are ease of setup, low cost of content and accessibility of the component base. +- [Features](#features) - [Demo access](#demo-access) - [Supported system](#supported-system) - [Quick installation](#quick-installation) @@ -49,6 +50,22 @@ The basic principles underlying the system being developed are ease of setup, lo - [See also](#see-also) - [License](#license) +### Features + +1. The ultimate smart thing solution - server, configurator, nodes, gateway, mobile application +2. Open API +3. Cross-platform Linux, MacOS, Windows ... +4. Convenient WEB-configurator for fine-tuning +5. Mobile application for equipment management +6. Role system for separation of access rights +7. Programs in javaScript, coffeeScript, typeScript +8. Notification system SMS, Email, Slack, Telegram +9. If MODBUS is small, you can work through calling external programs / scripts, which greatly expands the possibilities +10. Autonomous system. +11. Quick backup of all data, and recovery - literally in two teams +12. Have Docker images to enhance system security +13. Minimum consumption of resources. + ### Demo access [dashboard](https://board.e154.ru) (https://board.e154.ru)
diff --git a/README.ru.md b/README.ru.md index ee4aede60..aaa7eb0ab 100644 --- a/README.ru.md +++ b/README.ru.md @@ -31,6 +31,7 @@ Основные принципы лежащие в основе разрабатываемой системы - простота настройки, дешевизна содержания и доступность компонентной базы. +- [Features](#features) - [Demo](#demo-access) - [Поддерживаемые системы](#%D0%9F%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B6%D0%B8%D0%B2%D0%B0%D0%B5%D0%BC%D1%8B%D0%B5-%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B) - [Быстрая установка](#%D0%91%D1%8B%D1%81%D1%82%D1%80%D0%B0%D1%8F-%D1%83%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0) @@ -49,6 +50,22 @@ - [Коммерческие аналоги](#%D0%9A%D0%BE%D0%BC%D0%BC%D0%B5%D1%80%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B5-%D0%B0%D0%BD%D0%B0%D0%BB%D0%BE%D0%B3%D0%B8) - [License](#%D0%9B%D0%B8%D1%86%D0%B5%D0%BD%D0%B7%D0%B8%D1%8F) +### Features + +1. Законченное решение умных вещей, и для автоматизации процессов - сервер,конфигуратор,ноды,шлюз,мобильное приложение +2. Открытое API +3. Кроссплатформенность Linux,MacOS,Windows … +4. Удобный WEB конфигуратор для тонкой настройки +5. Мобильное приложение для управления устройствами +6. Система ролей для разделения прав доступа +7. Программы на javaScript, coffeeScript, typeScript +8. Система уведомлений SMS, Email, Slack, Telegram +9. Если MODBUS мало можно работать через вызовы внешних программ/скриптов, что сильно расширяет возможности +10. Автономная система, если не требуются уведомления и доступ из вне +11. Быстрое резервное копирование всех данных, и восстановление - буквально в две команды +12. Есть Docker образы для повышения безопасности системы +13. Минимальное потребление ресурсов, позволяет развернуть комплекс на слабом железе + ### Demo access [dashboard](https://board.e154.ru) (https://board.e154.ru)
diff --git a/adaptors/log.go b/adaptors/log.go index 61e908aaf..2a5131313 100644 --- a/adaptors/log.go +++ b/adaptors/log.go @@ -1,9 +1,10 @@ package adaptors import ( - "github.com/jinzhu/gorm" "github.com/e154/smart-home/db" m "github.com/e154/smart-home/models" + "github.com/jinzhu/gorm" + gormbulk "github.com/t-tiger/gorm-bulk-insert" ) type Log struct { @@ -28,6 +29,19 @@ func (n *Log) Add(ver *m.Log) (id int64, err error) { return } +func (n *Log) AddMultiple(items []*m.Log) (err error) { + + insertRecords := make([]interface{}, 0, len(items)) + for _, ver := range items { + dbVer := n.toDb(ver) + insertRecords = append(insertRecords, *dbVer) + } + + err = gormbulk.BulkInsert(n.db, insertRecords, len(insertRecords)) + + return +} + func (n *Log) GetById(verId int64) (ver *m.Log, err error) { var dbVer *db.Log diff --git a/common/validation.go b/common/validation.go new file mode 100644 index 000000000..917e19d9b --- /dev/null +++ b/common/validation.go @@ -0,0 +1,16 @@ +package common + +import "github.com/e154/smart-home/system/validation" + +type Validation struct { +} + +func (d Validation) Valid() (ok bool, errs []*validation.Error) { + + valid := validation.Validation{} + if ok, _ = valid.Valid(d); !ok { + errs = valid.Errors + } + + return +} diff --git a/container.go b/container.go index 4e3121113..583a54182 100644 --- a/container.go +++ b/container.go @@ -64,6 +64,7 @@ func BuildContainer() (container *dig.Container) { container.Provide(stream.NewHub) container.Provide(telemetry.NewTelemetry) container.Provide(logging.NewLogBackend) + container.Provide(logging.NewLogDbSaver) container.Provide(endpoint.NewEndpoint) container.Provide(gate_client.NewGateClient) container.Provide(notify.NewNotify) diff --git a/doc/config.yaml b/doc/config.yaml index 17bcb8cb6..fc72794ec 100644 --- a/doc/config.yaml +++ b/doc/config.yaml @@ -135,14 +135,14 @@ Languages: url: "#install-configuration-conf" - title: "Настройка ноды" url: "#install-node-conf" - - title: "База mysql" - url: "#install-mysql" + - title: "База postgres" + url: "#install-postgres" - title: "Запуск" url: "#install-exec" - title: "Обновление" url: "#update" - - title: "Обновление базы mysql" - url: "#migrate-mysql" + - title: "Обновление базы postgres" + url: "#migrate-postgres" - title: "Автозапуск" url: "#service" - title: "Сборка из исходного кода" @@ -351,14 +351,14 @@ Languages: url: "#install-configuration-conf" - title: "Install node conf" url: "#install-node-conf" - - title: "Install mysql" - url: "#install-mysql" + - title: "Install postgres" + url: "#install-postgres" - title: "Install exec" url: "#install-exec" - title: "Update" url: "#update" - - title: "Migrate mysql" - url: "#migrate-mysql" + - title: "Migrate postgres" + url: "#migrate-postgres" - title: "Run as service" url: "#service" - title: "Install from source" diff --git a/doc/content/getting-started/_install.en.md b/doc/content/getting-started/_install.en.md index c87e853a1..a361659d4 100644 --- a/doc/content/getting-started/_install.en.md +++ b/doc/content/getting-started/_install.en.md @@ -17,7 +17,7 @@ groups: * Настройка сервера * Настройка конфигуратора * Настройка ноды -* База mysql +* База postgres
@@ -88,101 +88,78 @@ tree ```bash cd /opt/smart-home/server -sed 's/dev\/app.conf/prod\/app.conf/' conf/app.sample.conf > conf/app.conf -cp conf/prod/app.sample.conf conf/prod/app.conf -cp conf/prod/db.sample.conf conf/prod/db.conf +cp conf/config.dev.conf conf/config.conf ``` -Основные значения: +Важные поля: -* **httpaddr** - адрес сервера REST API -* **httpport** - порт сервера REST API -* **data_dir** - директория хранения общих файлов -* **db_user** - пользователь для соединени mysql -* **db_pass** - пароль доступка к mysql -* **db_host** - адрес сервера mysql -* **db_name** - название базы mysql -* **db_port** - порт сервера mysql - -Для работы сервера требуется подключение к базе mysql. Отредактируйте файл */opt/smart-home/server/conf/prod/db.conf* +* **server_host** - адрес сервера REST API +* **server_port** - порт сервера REST API +* **pg_user** - пользователь для соединени postgresql +* **pg_pass** - пароль доступка к postgresql +* **pg_host** - адрес сервера postgresql +* **pg_name** - название базы postgresql +* **pg_port** - порт сервера postgresql ```bash -db_user = smarthome -db_pass = smarthome -db_host = "127.0.0.1" -db_name = smarthome -db_port = "3306" -db_type = mysql +pg_user = smart_home +pg_pass = smart_home +pg_host = "127.0.0.1" +pg_name = smart_home +pg_port = "5432" ```

Настройка конфигуратора

```bash cd /opt/smart-home/configurator -sed 's/dev\/app.conf/prod\/app.conf/' conf/app.sample.conf > conf/app.conf -cp conf/prod/app.sample.conf conf/prod/app.conf -cp conf/prod/db.sample.conf conf/prod/db.conf +cp conf/config.dev.conf conf/config.conf ``` Основные значения: * **httpaddr** - адрес веб интерфеса конфигуратора * **httpport** - порт веб интерфеса конфигуратора -* **serveraddr** - порт сервера REST API -* **serverport** - порт сервера REST API -* **data_dir** - директория хранения общих файлов +* **api_addr** - порт сервера REST API +* **api_port** - порт сервера REST API +* **api_scheme** - схема общения с сервером

Настройка ноды

```bash cd /opt/smart-home/node -cp conf/node.sample.conf conf/node.conf +cp conf/config.dev.conf conf/config.conf ``` Основные значения: -* **app_version** - версия внутреннего api ноды -* **ip** - адрес ожидания соединения от сервера -* **port** - порт ожидания соединения от сервера -* **baud** - скорость работы порта ввода вывода, используется если с сервера пришёл запрос на - обращение к устройству, но baud не был указан -* **timeout** - используется при обработке ошибок связи с устройствами -* **stopbits** - стоп бит, используется в общении с устройствами +* **name** - системное назание ноды (прим. node1) +* **topic** - канал для общения с сервером (прим. node1) +* **mqtt_keep_alive** - тонкие настройки (прим. 300) +* **mqtt_connect_timeout** - тонкие настройки (прим. 2) +* **mqtt_sessions_provider** - тонкие настройки (прим. "mem") +* **mqtt_topics_provider** - тонкие настройки (прим. "mem) +* **mqtt_username** - пользователь указанный при регистрации ноды на сервере +* **mqtt_password** - павроль указанный при регистрации ноды на сервере +* **mqtt_ip** - ip адрес сервера **умный дом** +* **mqtt_port** - порт для подключения нод к **умный дом** +* **serial** - спискок портов которые будет слушать нода для поиска устройств -

База mysql

- -Подключение к консоли mysql, потребуется пароль рута: - -```bash -mysql -u root -p -``` +

База postgres

-Создание базы сервера **умный дом**: +Подключение к консоли Postgresql, потребуется пароль рута: ```bash -CREATE DATABASE smarthome; +sudo -u postgres psql +postgres=# create database smart_home; +postgres=# create user smart_home with encrypted password 'smart_home'; +postgres=# grant all privileges on database smart_home to smart_home; ``` -Создание нового пользователя, с соответствующими правами **smarthome** из консоли mysql - -* **smarthome** - пользователь -* **smarthome** - пароль - - -```bash -CREATE USER 'smarthome'@'localhost' IDENTIFIED BY 'smarthome'; -GRANT ALL PRIVILEGES ON smarthome . * TO 'smarthome'@'localhost'; -FLUSH PRIVILEGES; -``` - -импорт базы - -```bash -use smarthome -source /opt/smart-home/server/dump.sql -``` +система базы данных имеет внтренный миханизм миграций. При подключении сервер проверяет текущую версию, +и запускает миграции если сервер их имеет.

Запуск

diff --git a/doc/content/getting-started/_install.md b/doc/content/getting-started/_install.md index c87e853a1..52c03702c 100644 --- a/doc/content/getting-started/_install.md +++ b/doc/content/getting-started/_install.md @@ -17,7 +17,7 @@ groups: * Настройка сервера * Настройка конфигуратора * Настройка ноды -* База mysql +* База postgres
@@ -88,101 +88,78 @@ tree ```bash cd /opt/smart-home/server -sed 's/dev\/app.conf/prod\/app.conf/' conf/app.sample.conf > conf/app.conf -cp conf/prod/app.sample.conf conf/prod/app.conf -cp conf/prod/db.sample.conf conf/prod/db.conf +cp conf/config.dev.conf conf/config.conf ``` -Основные значения: +Важные поля: -* **httpaddr** - адрес сервера REST API -* **httpport** - порт сервера REST API -* **data_dir** - директория хранения общих файлов -* **db_user** - пользователь для соединени mysql -* **db_pass** - пароль доступка к mysql -* **db_host** - адрес сервера mysql -* **db_name** - название базы mysql -* **db_port** - порт сервера mysql - -Для работы сервера требуется подключение к базе mysql. Отредактируйте файл */opt/smart-home/server/conf/prod/db.conf* +* **server_host** - адрес сервера REST API +* **server_port** - порт сервера REST API +* **pg_user** - пользователь для соединени postgresql +* **pg_pass** - пароль доступка к postgresql +* **pg_host** - адрес сервера postgresql +* **pg_name** - название базы postgresql +* **pg_port** - порт сервера postgresql ```bash -db_user = smarthome -db_pass = smarthome -db_host = "127.0.0.1" -db_name = smarthome -db_port = "3306" -db_type = mysql +pg_user = smart_home +pg_pass = smart_home +pg_host = "127.0.0.1" +pg_name = smart_home +pg_port = "5432" ```

Настройка конфигуратора

```bash cd /opt/smart-home/configurator -sed 's/dev\/app.conf/prod\/app.conf/' conf/app.sample.conf > conf/app.conf -cp conf/prod/app.sample.conf conf/prod/app.conf -cp conf/prod/db.sample.conf conf/prod/db.conf +cp conf/config.dev.conf conf/config.conf ``` Основные значения: * **httpaddr** - адрес веб интерфеса конфигуратора * **httpport** - порт веб интерфеса конфигуратора -* **serveraddr** - порт сервера REST API -* **serverport** - порт сервера REST API -* **data_dir** - директория хранения общих файлов +* **api_addr** - порт сервера REST API +* **api_port** - порт сервера REST API +* **api_scheme** - схема общения с сервером

Настройка ноды

```bash cd /opt/smart-home/node -cp conf/node.sample.conf conf/node.conf +cp conf/config.dev.conf conf/config.conf ``` Основные значения: -* **app_version** - версия внутреннего api ноды -* **ip** - адрес ожидания соединения от сервера -* **port** - порт ожидания соединения от сервера -* **baud** - скорость работы порта ввода вывода, используется если с сервера пришёл запрос на - обращение к устройству, но baud не был указан -* **timeout** - используется при обработке ошибок связи с устройствами -* **stopbits** - стоп бит, используется в общении с устройствами +* **name** - системное назание ноды (прим. node1) +* **topic** - канал для общения с сервером (прим. node1) +* **mqtt_keep_alive** - тонкие настройки (прим. 300) +* **mqtt_connect_timeout** - тонкие настройки (прим. 2) +* **mqtt_sessions_provider** - тонкие настройки (прим. "mem") +* **mqtt_topics_provider** - тонкие настройки (прим. "mem) +* **mqtt_username** - пользователь указанный при регистрации ноды на сервере +* **mqtt_password** - павроль указанный при регистрации ноды на сервере +* **mqtt_ip** - ip адрес сервера **умный дом** +* **mqtt_port** - порт для подключения нод к **умный дом** +* **serial** - спискок портов которые будет слушать нода для поиска устройств -

База mysql

- -Подключение к консоли mysql, потребуется пароль рута: - -```bash -mysql -u root -p -``` +

База Postgresql

-Создание базы сервера **умный дом**: +Подключение к консоли Postgresql, потребуется пароль рута: ```bash -CREATE DATABASE smarthome; +sudo -u postgres psql +postgres=# create database smart_home; +postgres=# create user smart_home with encrypted password 'smart_home'; +postgres=# grant all privileges on database smart_home to smart_home; ``` -Создание нового пользователя, с соответствующими правами **smarthome** из консоли mysql - -* **smarthome** - пользователь -* **smarthome** - пароль - - -```bash -CREATE USER 'smarthome'@'localhost' IDENTIFIED BY 'smarthome'; -GRANT ALL PRIVILEGES ON smarthome . * TO 'smarthome'@'localhost'; -FLUSH PRIVILEGES; -``` - -импорт базы - -```bash -use smarthome -source /opt/smart-home/server/dump.sql -``` +система базы данных имеет внтренный миханизм миграций. При подключении сервер проверяет текущую версию, +и запускает миграции если сервер их имеет.

Запуск

diff --git a/doc/content/getting-started/_install_from_source.en.md b/doc/content/getting-started/_install_from_source.en.md index 41d934245..2995873f9 100644 --- a/doc/content/getting-started/_install_from_source.en.md +++ b/doc/content/getting-started/_install_from_source.en.md @@ -20,8 +20,7 @@ mkdir -p /opt/smart-home/server mkdir -p /opt/smart-home/configurator mkdir -p /opt/smart-home/node mkdir ~/smart-home -go get github.com/FiloSottile/gvt -go get github.com/beego/bee +go get -u github.com/golang/dep/cmd/dep sudo npm install -g bower sudo npm install -g hulp ``` @@ -32,12 +31,12 @@ sudo npm install -g hulp cd ~/smart-home git clone git@github.com:e154/smart-home.git cd smart-home -gvt restore +dep ensure go build -o server cp -r conf /opt/smart-home/server cp -r data /opt/smart-home cp server /opt/smart-home/server -sed 's/dev\/app.sample.conf/prod\/app.sample.conf/' conf/app.sample.conf > /opt/smart-home/server/conf/app.sample.conf +cp conf/config.dev.conf /opt/smart-home/server/conf/config.conf ``` ### Сборка конфигуратора {#install-from-source-configurator} @@ -46,11 +45,11 @@ sed 's/dev\/app.sample.conf/prod\/app.sample.conf/' conf/app.sample.conf > /opt/ cd ~/smart-home git clone git@github.com:e154/smart-home-configurator.git cd smart-home-configurator -gvt restore +dep ensure go build -o configurator cp configurator /opt/smart-home/configurator cp -r conf /opt/smart-home/configurator -sed 's/dev\/app.sample.conf/prod\/app.sample.conf/' conf/app.sample.conf > /opt/smart-home/configurator/conf/app.sample.conf +cp conf/config.dev.conf /opt/smart-home/configurator/conf/config.conf cd static_source npm install @@ -74,7 +73,7 @@ cp -r build /opt/smart-home/configurator cd ~/smart-home git clone git@github.com:e154/smart-home-node.git cd smart-home-node -gvt restore +dep ensure go build -o node cp node /opt/smart-home/node cp -r conf /opt/smart-home/node diff --git a/doc/content/getting-started/_install_from_source.md b/doc/content/getting-started/_install_from_source.md index 41d934245..2995873f9 100644 --- a/doc/content/getting-started/_install_from_source.md +++ b/doc/content/getting-started/_install_from_source.md @@ -20,8 +20,7 @@ mkdir -p /opt/smart-home/server mkdir -p /opt/smart-home/configurator mkdir -p /opt/smart-home/node mkdir ~/smart-home -go get github.com/FiloSottile/gvt -go get github.com/beego/bee +go get -u github.com/golang/dep/cmd/dep sudo npm install -g bower sudo npm install -g hulp ``` @@ -32,12 +31,12 @@ sudo npm install -g hulp cd ~/smart-home git clone git@github.com:e154/smart-home.git cd smart-home -gvt restore +dep ensure go build -o server cp -r conf /opt/smart-home/server cp -r data /opt/smart-home cp server /opt/smart-home/server -sed 's/dev\/app.sample.conf/prod\/app.sample.conf/' conf/app.sample.conf > /opt/smart-home/server/conf/app.sample.conf +cp conf/config.dev.conf /opt/smart-home/server/conf/config.conf ``` ### Сборка конфигуратора {#install-from-source-configurator} @@ -46,11 +45,11 @@ sed 's/dev\/app.sample.conf/prod\/app.sample.conf/' conf/app.sample.conf > /opt/ cd ~/smart-home git clone git@github.com:e154/smart-home-configurator.git cd smart-home-configurator -gvt restore +dep ensure go build -o configurator cp configurator /opt/smart-home/configurator cp -r conf /opt/smart-home/configurator -sed 's/dev\/app.sample.conf/prod\/app.sample.conf/' conf/app.sample.conf > /opt/smart-home/configurator/conf/app.sample.conf +cp conf/config.dev.conf /opt/smart-home/configurator/conf/config.conf cd static_source npm install @@ -74,7 +73,7 @@ cp -r build /opt/smart-home/configurator cd ~/smart-home git clone git@github.com:e154/smart-home-node.git cd smart-home-node -gvt restore +dep ensure go build -o node cp node /opt/smart-home/node cp -r conf /opt/smart-home/node diff --git a/doc/content/getting-started/_overview.en.md b/doc/content/getting-started/_overview.en.md index 6ba1dc5c3..aa417a467 100644 --- a/doc/content/getting-started/_overview.en.md +++ b/doc/content/getting-started/_overview.en.md @@ -17,31 +17,34 @@ groups: Создавать сценарии, и реакции на события в веб интерфейсе конфигуртора через гибкую систему скриптов. Управлять состоянием устройств из любой подсети, где доступен управляющий сервер. -Пример простого устройства [умная розетка](https://github.com/e154/smart-home-socket), позволяет управлять нагрузкой 220в 14А ампер. +Пример простого устройства [контроллер](https://github.com/e154/smart-home-modbus-ctrl-v1/), позволяет управлять нагрузкой 220в 14А ампер. На базе которого легко построить решение для управления светом, рольставнями, воротами, датчики протечки, утечки газа, и много другого Программный комплекс **Умный дом** имеет модульную структуру, и состоит из следующих частей: -**Сервер** - Основной системный модуль, предоставление api для внешних служб, контроль доступа, +**Сервер** - Основной системный модуль, предоставление api для внешних служб, контроль доступа, исполнение процессов, логирование, оповещенние, реакция на события, исполнени сценариев. -**Конфигуратор** - Клиентский модуль подключается к серверу по API, позволяет конфигурировать +**Конфигуратор** - Клиентский модуль подключается к серверу по API, позволяет конфигурировать систему под свои нужды, требуется как првило на этапе конфигурации. -**Нода** - посредник связи сервера с активными устройствами, позволяет связать один сервер с +**Нода** - посредник связи сервера с активными устройствами, позволяет связать один сервер с множеством териториально удалённых устройств по сети интернет, локальной сети, или по различным шифрованным туннелям. -Работает по принципу клиент сервер. Стартует и ожидает соединения на заданном ADDRESS:PORT. Сервер подключается к ноде -по требованию сценария, либо доступности последней. +Работает по принципу клиент сервер. -~~**Монитор** - мобильное клиентское приложение android, ios.~~(в разработке) +**Мобильный шлюз** - Сервис позволяющий, получить доступ к умному дому для мобильных коиентов + +**Мобильное приложение** - кромплтформенное клиентское приложение для взаимодействия с Вашими устройствами в android, ios. Для работы **системы умного дома** требуется запущенный сервер, и минимум одна локальная нода, либо одна запущенная нода в том же сегменте сети. Конфигуратор требуется только на этапе конфигурации. -На данный момент общение с исполнительными устройствами возможно только по адаптированному портоколу modbus. +Умный дом позволяет работать с устройствами чере протокол MODBUS, SMARTBUS, или выполнение произвольный комманд/скриптов, с последующей обраблткой ответа. В дальнейшем этот список будет расширен. Если Вам требуется добавить какой-то свой вид связи, напишите нам, либо -создайте реквест с предложением в репозиторий Сервер, Нода. +создайте реквест с предложением в репозиторий Сервер, Нода + +Пример минимального устройства работающего на шине MODBUS [контроллер](https://github.com/e154/smart-home-modbus-ctrl-v1/). Модифицированный modbus подразумевает соответствующее установленное ПО на ваше исполнительное устройство, простой пример устройства со схемой и программой прошивки для **AVR mega 168pu** управляющего розетой, легко поддающееся модификации под более сложные задачи можно @@ -51,3 +54,19 @@ groups: Схематичная сеть **системы умного дома**: ![Схематичная сеть умного дома](/smart-home/img/smart-home-network.svg "Схематичная сеть умного дома") + + + +1. Законченное решение умных вещей, и для автоматизации процессов - сервер,конфигуратор,ноды,шлюз,мобильное приложение +2. Открытое API +3. Кроссплатформенность Linux,MacOS,Windows … +4. Удобный WEB конфигуратор для тонкой настройки +5. Мобильное приложение для управления устройствами +6. Система ролей для разделения прав доступа +7. Программы на javaScript, coffeeScript, typeScript +8. Система уведомлений SMS, Email, Slack, Telegram +9. Если MODBUS мало можно работать через вызовы внешних программ/скриптов, что сильно расширяет возможности +10. Автономная система, если не требуются уведомления и доступ из вне +11. Быстрое резервное копирование всех данных, и восстановление - буквально в две команды +12. Есть Docker образы для повышения безопасности системы +13. Минимальное потребление ресурсов, позволяет развернуть комплекс на слабом железе \ No newline at end of file diff --git a/doc/content/getting-started/_overview.md b/doc/content/getting-started/_overview.md index 6ba1dc5c3..aa417a467 100644 --- a/doc/content/getting-started/_overview.md +++ b/doc/content/getting-started/_overview.md @@ -17,31 +17,34 @@ groups: Создавать сценарии, и реакции на события в веб интерфейсе конфигуртора через гибкую систему скриптов. Управлять состоянием устройств из любой подсети, где доступен управляющий сервер. -Пример простого устройства [умная розетка](https://github.com/e154/smart-home-socket), позволяет управлять нагрузкой 220в 14А ампер. +Пример простого устройства [контроллер](https://github.com/e154/smart-home-modbus-ctrl-v1/), позволяет управлять нагрузкой 220в 14А ампер. На базе которого легко построить решение для управления светом, рольставнями, воротами, датчики протечки, утечки газа, и много другого Программный комплекс **Умный дом** имеет модульную структуру, и состоит из следующих частей: -**Сервер** - Основной системный модуль, предоставление api для внешних служб, контроль доступа, +**Сервер** - Основной системный модуль, предоставление api для внешних служб, контроль доступа, исполнение процессов, логирование, оповещенние, реакция на события, исполнени сценариев. -**Конфигуратор** - Клиентский модуль подключается к серверу по API, позволяет конфигурировать +**Конфигуратор** - Клиентский модуль подключается к серверу по API, позволяет конфигурировать систему под свои нужды, требуется как првило на этапе конфигурации. -**Нода** - посредник связи сервера с активными устройствами, позволяет связать один сервер с +**Нода** - посредник связи сервера с активными устройствами, позволяет связать один сервер с множеством териториально удалённых устройств по сети интернет, локальной сети, или по различным шифрованным туннелям. -Работает по принципу клиент сервер. Стартует и ожидает соединения на заданном ADDRESS:PORT. Сервер подключается к ноде -по требованию сценария, либо доступности последней. +Работает по принципу клиент сервер. -~~**Монитор** - мобильное клиентское приложение android, ios.~~(в разработке) +**Мобильный шлюз** - Сервис позволяющий, получить доступ к умному дому для мобильных коиентов + +**Мобильное приложение** - кромплтформенное клиентское приложение для взаимодействия с Вашими устройствами в android, ios. Для работы **системы умного дома** требуется запущенный сервер, и минимум одна локальная нода, либо одна запущенная нода в том же сегменте сети. Конфигуратор требуется только на этапе конфигурации. -На данный момент общение с исполнительными устройствами возможно только по адаптированному портоколу modbus. +Умный дом позволяет работать с устройствами чере протокол MODBUS, SMARTBUS, или выполнение произвольный комманд/скриптов, с последующей обраблткой ответа. В дальнейшем этот список будет расширен. Если Вам требуется добавить какой-то свой вид связи, напишите нам, либо -создайте реквест с предложением в репозиторий Сервер, Нода. +создайте реквест с предложением в репозиторий Сервер, Нода + +Пример минимального устройства работающего на шине MODBUS [контроллер](https://github.com/e154/smart-home-modbus-ctrl-v1/). Модифицированный modbus подразумевает соответствующее установленное ПО на ваше исполнительное устройство, простой пример устройства со схемой и программой прошивки для **AVR mega 168pu** управляющего розетой, легко поддающееся модификации под более сложные задачи можно @@ -51,3 +54,19 @@ groups: Схематичная сеть **системы умного дома**: ![Схематичная сеть умного дома](/smart-home/img/smart-home-network.svg "Схематичная сеть умного дома") + + + +1. Законченное решение умных вещей, и для автоматизации процессов - сервер,конфигуратор,ноды,шлюз,мобильное приложение +2. Открытое API +3. Кроссплатформенность Linux,MacOS,Windows … +4. Удобный WEB конфигуратор для тонкой настройки +5. Мобильное приложение для управления устройствами +6. Система ролей для разделения прав доступа +7. Программы на javaScript, coffeeScript, typeScript +8. Система уведомлений SMS, Email, Slack, Telegram +9. Если MODBUS мало можно работать через вызовы внешних программ/скриптов, что сильно расширяет возможности +10. Автономная система, если не требуются уведомления и доступ из вне +11. Быстрое резервное копирование всех данных, и восстановление - буквально в две команды +12. Есть Docker образы для повышения безопасности системы +13. Минимальное потребление ресурсов, позволяет развернуть комплекс на слабом железе \ No newline at end of file diff --git a/doc/content/getting-started/_quick_install.en.md b/doc/content/getting-started/_quick_install.en.md index 8b8ec5be6..afb5f75c6 100644 --- a/doc/content/getting-started/_quick_install.en.md +++ b/doc/content/getting-started/_quick_install.en.md @@ -10,7 +10,7 @@ groups: * Подразумевается что у это первая установка в систему * Установка будет проходить в автоматическом режиме * Директория установки /opt/smart-home -* После установки потребуется настроить подключение к серверу баз данных mysql +* После установки потребуется настроить подключение к серверу баз данных postgresql Установка сервера @@ -30,16 +30,13 @@ curl -sSL http://e154.github.io/smart-home/configurator-installer.sh | bash /dev curl -sSL http://e154.github.io/smart-home/node-installer.sh | bash /dev/stdin --install ``` -Нвстройка сервера баз данных mysql +Нвстройка сервера баз данных postgresql ```bash -mysql -u root -p -CREATE DATABASE smarthome; -CREATE USER 'smarthome'@'localhost' IDENTIFIED BY 'smarthome'; -GRANT ALL PRIVILEGES ON smarthome . * TO 'smarthome'@'localhost'; -FLUSH PRIVILEGES; -use smarthome -source /opt/smart-home/server/dump.sql +sudo -u postgres psql +postgres=# create database smart_home; +postgres=# create user smart_home with encrypted password 'smart_home'; +postgres=# grant all privileges on database smart_home to smart_home; ``` Запуск сервера diff --git a/doc/content/getting-started/_quick_install.md b/doc/content/getting-started/_quick_install.md index 8b8ec5be6..afb5f75c6 100644 --- a/doc/content/getting-started/_quick_install.md +++ b/doc/content/getting-started/_quick_install.md @@ -10,7 +10,7 @@ groups: * Подразумевается что у это первая установка в систему * Установка будет проходить в автоматическом режиме * Директория установки /opt/smart-home -* После установки потребуется настроить подключение к серверу баз данных mysql +* После установки потребуется настроить подключение к серверу баз данных postgresql Установка сервера @@ -30,16 +30,13 @@ curl -sSL http://e154.github.io/smart-home/configurator-installer.sh | bash /dev curl -sSL http://e154.github.io/smart-home/node-installer.sh | bash /dev/stdin --install ``` -Нвстройка сервера баз данных mysql +Нвстройка сервера баз данных postgresql ```bash -mysql -u root -p -CREATE DATABASE smarthome; -CREATE USER 'smarthome'@'localhost' IDENTIFIED BY 'smarthome'; -GRANT ALL PRIVILEGES ON smarthome . * TO 'smarthome'@'localhost'; -FLUSH PRIVILEGES; -use smarthome -source /opt/smart-home/server/dump.sql +sudo -u postgres psql +postgres=# create database smart_home; +postgres=# create user smart_home with encrypted password 'smart_home'; +postgres=# grant all privileges on database smart_home to smart_home; ``` Запуск сервера diff --git a/doc/content/getting-started/_requirements.en.md b/doc/content/getting-started/_requirements.en.md index 26e337efb..7b03f2eb1 100644 --- a/doc/content/getting-started/_requirements.en.md +++ b/doc/content/getting-started/_requirements.en.md @@ -108,7 +108,7 @@ groups: * **dump.sql** - дамп sql базы данных * **LICENSE** - текстовый файл лицензионного соглашения * **README.md** - текстовый файл краткой вводной информации -* **server-** - Платформо зависимый исполняемый файл +* **server** - Платформо зависимый исполняемый файл

Конфигуратор

@@ -141,7 +141,7 @@ groups: * **LICENSE** - текстовый файл лицензионного соглашения * **README.md** - текстовый файл краткой вводной информации * **contributors.txt** - текстовый файл, список разработчиков системы умный дом -* **configurator-** - Платформо зависимый исполняемый файл +* **configurator** - Платформо зависимый исполняемый файл

Нода

@@ -170,6 +170,6 @@ groups: * **LICENSE** - текстовый файл лицензионного соглашения * **README.md** - текстовый файл краткой вводной информации * **contributors.txt** - текстовый файл, список разработчиков системы умный дом -* **node-** - Платформо зависимый исполняемый файл +* **node** - Платформо зависимый исполняемый файл diff --git a/doc/content/getting-started/_requirements.md b/doc/content/getting-started/_requirements.md index 26e337efb..951cf5a53 100644 --- a/doc/content/getting-started/_requirements.md +++ b/doc/content/getting-started/_requirements.md @@ -85,7 +85,6 @@ groups: ├── conf ├── contributors.txt ├── data -├── dump.sql ├── LICENSE ├── README.md ├── server-darwin-10.6-386 @@ -105,10 +104,9 @@ groups: * **conf** - директория конфигурационных файлов * **contributors.txt** - текстовый файл, список разработчиков системы умный дом * **data** - директория хранения рабочих файлов иконки, изображения -* **dump.sql** - дамп sql базы данных * **LICENSE** - текстовый файл лицензионного соглашения * **README.md** - текстовый файл краткой вводной информации -* **server-** - Платформо зависимый исполняемый файл +* **server** - Платформо зависимый исполняемый файл

Конфигуратор

@@ -141,7 +139,7 @@ groups: * **LICENSE** - текстовый файл лицензионного соглашения * **README.md** - текстовый файл краткой вводной информации * **contributors.txt** - текстовый файл, список разработчиков системы умный дом -* **configurator-** - Платформо зависимый исполняемый файл +* **configurator** - Платформо зависимый исполняемый файл

Нода

@@ -170,6 +168,6 @@ groups: * **LICENSE** - текстовый файл лицензионного соглашения * **README.md** - текстовый файл краткой вводной информации * **contributors.txt** - текстовый файл, список разработчиков системы умный дом -* **node-** - Платформо зависимый исполняемый файл +* **node** - Платформо зависимый исполняемый файл diff --git a/doc/content/getting-started/_update.en.md b/doc/content/getting-started/_update.en.md index 0933690e8..516112c97 100644 --- a/doc/content/getting-started/_update.en.md +++ b/doc/content/getting-started/_update.en.md @@ -16,28 +16,7 @@ groups: * Конфигуратор * Нода -

Обновление базы mysql

+

Обновление базы postgres

-База поддерживает версионирование, перед обновление структуры нужно создать резервную копию - -```bash -./opt/smart-home/server/examples/scripts/backup.sh -Starting backup to 19-02-2017-22-06-30-dump.sql... -``` - -Скрипт создаст копию действующей базы в */opt/smart-home/backup* - -Запуск обновления базы: - -```bash -cd /opt/smart-home/server/ -./server-linux-amd64 migrate -2017/02/19 01:59:37 GOPATH: /home/delta54/workspace/golang/src/github.com/e154/smart-home/migrate.go 81 /home/delta54/workspace/golang -2017/02/19 01:59:37 Using 'mysql' as 'driver' -2017/02/19 01:59:37 Using 'smarthome:smarthome@tcp(127.0.0.1:3306)/smarthome_dev?charset=utf8' as 'conn' -2017/02/19 01:59:37 Running all outstanding migrations -2017/02/19 01:59:40 |> 2017/02/19 01:59:38 [I] total success upgrade: 0 migration -2017/02/19 01:59:40 Migration successful! -``` - -Сообщение *Migration successful* говорит о успешно выполненной миграции \ No newline at end of file +система базы данных имеет внтренный миханизм миграций. При подключении сервер проверяет текущую версию, +и запускает миграции если сервер их имеет. Ручное вмешательство для обновления БД не требуется. diff --git a/doc/content/getting-started/_update.md b/doc/content/getting-started/_update.md index 0933690e8..516112c97 100644 --- a/doc/content/getting-started/_update.md +++ b/doc/content/getting-started/_update.md @@ -16,28 +16,7 @@ groups: * Конфигуратор * Нода -

Обновление базы mysql

+

Обновление базы postgres

-База поддерживает версионирование, перед обновление структуры нужно создать резервную копию - -```bash -./opt/smart-home/server/examples/scripts/backup.sh -Starting backup to 19-02-2017-22-06-30-dump.sql... -``` - -Скрипт создаст копию действующей базы в */opt/smart-home/backup* - -Запуск обновления базы: - -```bash -cd /opt/smart-home/server/ -./server-linux-amd64 migrate -2017/02/19 01:59:37 GOPATH: /home/delta54/workspace/golang/src/github.com/e154/smart-home/migrate.go 81 /home/delta54/workspace/golang -2017/02/19 01:59:37 Using 'mysql' as 'driver' -2017/02/19 01:59:37 Using 'smarthome:smarthome@tcp(127.0.0.1:3306)/smarthome_dev?charset=utf8' as 'conn' -2017/02/19 01:59:37 Running all outstanding migrations -2017/02/19 01:59:40 |> 2017/02/19 01:59:38 [I] total success upgrade: 0 migration -2017/02/19 01:59:40 Migration successful! -``` - -Сообщение *Migration successful* говорит о успешно выполненной миграции \ No newline at end of file +система базы данных имеет внтренный миханизм миграций. При подключении сервер проверяет текущую версию, +и запускает миграции если сервер их имеет. Ручное вмешательство для обновления БД не требуется. diff --git a/doc/content/javascript/_map.en.md b/doc/content/javascript/_map.en.md index 5397a69fe..e640b3207 100644 --- a/doc/content/javascript/_map.en.md +++ b/doc/content/javascript/_map.en.md @@ -15,23 +15,44 @@ map = IC.Map Доступные методы приведены далее: -### .SetElementState(element, state) {#ic_map_set_element_state} +### .SetElementState(deviceModel, elementName, newState) {#ic_map_set_element_state} ```coffeescript -IC.Map.SetElementState(device, state) +IC.Map.SetElementState(device.getModel(), state) +``` + +**На входе** + +**Значение** | **Описание** +------------------------|-------------- + `deviceModel` | type: Object, ссылка на объект [DeviceModel{}](#device) + `elementName` | type: string, наименование элемента + `stnewStateate` | type: string, системное наименование состояния + +### .GetElement(device, elementName) {#ic_map_get_element} + +```coffeescript +elements = IC.Map.GetElement(device, elementName) ``` **На входе** **Значение** | **Описание** ----------------|-------------- - `element` | type: Object, ссылка на объект карты - `state` | type: string, системное наименование состояния + `device` | type: Object, ссылка на объект [Device{}](#device) + `elementName` | type: string, наименование элемента -### .GetElement(device) {#ic_map_get_element} + +**На выходе** + +**Значение** | **Описание** +----------------|-------------- + `elements` | type: Object, ссылка на объектов [MapElement{}](#map_element) + +### .GetElements(device) {#ic_map_get_element} ```coffeescript -element = IC.Map.GetElement(device) +elements = IC.Map.GetElement(device) ``` **На входе** @@ -40,9 +61,8 @@ element = IC.Map.GetElement(device) ----------------|-------------- `device` | type: Object, ссылка на объект [Device{}](#device) - **На выходе** **Значение** | **Описание** ----------------|-------------- - `element` | type: Object, ссылка на объект [MapElement{}](#map_element) + `elements` | type: Array, массив объектов [MapElement{}](#map_element) diff --git a/doc/content/javascript/_map.md b/doc/content/javascript/_map.md index fcadbf5a6..e640b3207 100644 --- a/doc/content/javascript/_map.md +++ b/doc/content/javascript/_map.md @@ -15,17 +15,17 @@ map = IC.Map Доступные методы приведены далее: -### .SetElementState(device, elementName, newState) {#ic_map_set_element_state} +### .SetElementState(deviceModel, elementName, newState) {#ic_map_set_element_state} ```coffeescript -IC.Map.SetElementState(device, state) +IC.Map.SetElementState(device.getModel(), state) ``` **На входе** **Значение** | **Описание** ------------------------|-------------- - `device` | type: Object, ссылка на объект [Device{}](#device) + `deviceModel` | type: Object, ссылка на объект [DeviceModel{}](#device) `elementName` | type: string, наименование элемента `stnewStateate` | type: string, системное наименование состояния diff --git a/models/device.go b/models/device.go index 61277a8f4..0a7cc600e 100644 --- a/models/device.go +++ b/models/device.go @@ -1,13 +1,13 @@ package models import ( - "time" - "github.com/e154/smart-home/system/validation" "encoding/json" + "fmt" . "github.com/e154/smart-home/common" . "github.com/e154/smart-home/models/devices" + "github.com/e154/smart-home/system/validation" "github.com/mitchellh/mapstructure" - "fmt" + "time" ) type Device struct { @@ -38,8 +38,10 @@ func (d *Device) Valid() (ok bool, errs []*validation.Error) { var out interface{} switch d.Type { - case DevTypeModbus: - out = &DevModBusConfig{} + case DevTypeModbusRtu: + out = &DevModBusRtuConfig{} + case DevTypeModbusTcp: + out = &DevModBusTcpConfig{} case DevTypeSmartBus: out = &DevSmartBusConfig{} case DevTypeCommand: @@ -73,8 +75,11 @@ func (d *Device) SetProperties(properties interface{}) (ok bool, errs []*validat var dType DeviceType switch v := properties.(type) { - case *DevModBusConfig: - dType = DevTypeModbus + case *DevModBusRtuConfig: + dType = DevTypeModbusRtu + ok, errs = v.Valid() + case *DevModBusTcpConfig: + dType = DevTypeModbusTcp ok, errs = v.Valid() case *DevSmartBusConfig: dType = DevTypeSmartBus @@ -103,8 +108,12 @@ func (d *Device) SetPropertiesFromMap(properties map[string]interface{}) (ok boo var out interface{} switch d.Type { - case DevTypeModbus: - out = &DevModBusConfig{} + case DevTypeModbusRtu: + out = &DevModBusRtuConfig{} + case DevTypeModbusTcp: + out = &DevModBusTcpConfig{} + //case DevTypeModbus: + // out = &DevModBusConfig{} case DevTypeSmartBus: out = &DevSmartBusConfig{} case DevTypeCommand: @@ -122,4 +131,4 @@ func (d *Device) SetPropertiesFromMap(properties map[string]interface{}) (ok boo ok, errs = d.SetProperties(out) return -} \ No newline at end of file +} diff --git a/models/devices/modbus.go b/models/devices/modbus.go index 96b16d8cc..48be5f380 100644 --- a/models/devices/modbus.go +++ b/models/devices/modbus.go @@ -2,11 +2,11 @@ package devices import ( . "github.com/e154/smart-home/common" - "github.com/e154/smart-home/system/validation" ) const ( - DevTypeModbus = DeviceType("modbus") + DevTypeModbusRtu = DeviceType("modbus_rtu") + DevTypeModbusTcp = DeviceType("modbus_tcp") // bit access ReadCoils = "ReadCoils" @@ -22,7 +22,8 @@ const ( WriteMultipleRegisters = "WriteMultipleRegisters" ) -type DevModBusConfig struct { +type DevModBusRtuConfig struct { + Validation SlaveId int `json:"slave_id" mapstructure:"slave_id"` // 1-32 Baud int `json:"baud"` // 9600, 19200, ... DataBits int `json:"data_bits" mapstructure:"data_bits"` // 5-9 @@ -31,14 +32,9 @@ type DevModBusConfig struct { Timeout int `json:"timeout"` // milliseconds } -func (d DevModBusConfig) Valid() (ok bool, errs []*validation.Error) { - - valid := validation.Validation{} - if ok, _ = valid.Valid(d); !ok { - errs = valid.Errors - } - - return +type DevModBusTcpConfig struct { + Validation + AddressPort string `json:"address_port" mapstructure:"address_port"` } type DevModBusRequest struct { diff --git a/system/core/device.go b/system/core/device.go index 8666a6112..ed6698b2c 100644 --- a/system/core/device.go +++ b/system/core/device.go @@ -1,9 +1,9 @@ package core import ( + "encoding/json" m "github.com/e154/smart-home/models" . "github.com/e154/smart-home/models/devices" - "encoding/json" ) type Device struct { @@ -68,7 +68,16 @@ func (d *Device) SmartBus(command []byte) (result *DevSmartBusResponse) { return } -func (d *Device) ModbusBus(f string, address, count uint16, command []uint16) (result *DevModBusResponse) { +func (d *Device) ModBus(f string, address, count uint16, command []uint16) (result *DevModBusResponse) { + + if d.dev.Type == DevTypeModbusRtu && d.node.stat.Thread == 0 { + result = &DevModBusResponse{ + BaseResponse: BaseResponse{ + Error: "no serial device", + }, + } + return + } request := &DevModBusRequest{ Function: f, @@ -88,7 +97,7 @@ func (d *Device) ModbusBus(f string, address, count uint16, command []uint16) (r nodeResult, err := d.node.Send(d.dev, data) if err != nil { result.Error = err.Error() - log.Error(err.Error()) + //log.Error(err.Error()) return } diff --git a/system/core/device_bind.go b/system/core/device_bind.go index cf2e50ef3..1cd13dd75 100644 --- a/system/core/device_bind.go +++ b/system/core/device_bind.go @@ -9,6 +9,7 @@ import ( // // Device // .getName() +// .getModel() // .getDescription() // .runCommand(command []string) // .smartBus(command []byte) @@ -51,6 +52,6 @@ func (d *DeviceBind) ModBus(f string, address, count uint16, command []uint16) ( dev: d.model, node: d.node, } - result = dev.ModbusBus(f, address, count, command) + result = dev.ModBus(f, address, count, command) return } \ No newline at end of file diff --git a/system/core/map_bind.go b/system/core/map_bind.go index bfbc23d4e..9c3f8a50d 100644 --- a/system/core/map_bind.go +++ b/system/core/map_bind.go @@ -1,5 +1,9 @@ package core +import ( + m "github.com/e154/smart-home/models" +) + // Javascript Binding // // map @@ -11,12 +15,12 @@ type MapBind struct { Map *Map } -func (e *MapBind) SetElementState(device *DeviceBind, elementName, newState string) { +func (e *MapBind) SetElementState(device *m.Device, elementName, newState string) { if device == nil { log.Error("device is nil") return } - e.Map.SetElementState(device.model, elementName, newState) + e.Map.SetElementState(device, elementName, newState) } func (e *MapBind) GetElement(device *DeviceBind, elementName string) (element *MapElementBind) { diff --git a/system/core/node.go b/system/core/node.go index 451e3a109..47d1139dc 100644 --- a/system/core/node.go +++ b/system/core/node.go @@ -15,13 +15,11 @@ type Nodes []*Node type Node struct { *m.Node - errors int64 - ConnStatus string - qClient *mqtt.Client - IsConnected bool - lastPing time.Time - quit bool - stat *NodeStatModel + errors int64 + ConnStatus string + mqttClient *mqtt.Client + lastPing time.Time + stat *NodeStatModel sync.Mutex ch map[int64]chan *NodeResponse } @@ -29,31 +27,19 @@ type Node struct { func NewNode(model *m.Node, mqtt *mqtt.Mqtt) *Node { + mqttClient, err := mqtt.NewClient(fmt.Sprintf("/home/%s", model.Name)) + if err != nil { + log.Error(err.Error()) + } + node := &Node{ Node: model, ConnStatus: "disabled", ch: make(map[int64]chan *NodeResponse, 0), stat: &NodeStatModel{}, + mqttClient: mqttClient, } - topic := fmt.Sprintf("/home/%s", model.Name) - mqttClient, err := mqtt.NewClient(topic) - if err != nil { - log.Error(err.Error()) - } - - node.qClient = mqttClient - - go func() { - for ; ; { - if node.quit { - break - } - time.Sleep(time.Second) - node.IsConnected = time.Now().Sub(node.lastPing).Seconds() < 2 && node.stat.Thread > 0 - } - }() - return node } @@ -77,7 +63,7 @@ func (n *Node) Send(device *m.Device, command []byte) (result NodeResponse, err } data, _ := json.Marshal(msg) - if err = n.qClient.Publish(data); err != nil { + if err = n.mqttClient.Publish(data); err != nil { log.Error(err.Error()) return } @@ -167,18 +153,18 @@ func (n *Node) onPublish(msg *message.PublishMessage) (err error) { func (n *Node) Connect() *Node { - if err := n.qClient.Connect(); err != nil { + if err := n.mqttClient.Connect(); err != nil { log.Error(err.Error()) } time.Sleep(time.Second) topic := fmt.Sprintf("/home/%s", n.Name) - if err := n.qClient.Subscribe(topic+"/resp", nil, n.onPublish); err != nil { + if err := n.mqttClient.Subscribe(topic+"/resp", nil, n.onPublish); err != nil { log.Warning(err.Error()) } - if err := n.qClient.Subscribe(topic+"/ping", nil, n.ping); err != nil { + if err := n.mqttClient.Subscribe(topic+"/ping", nil, n.ping); err != nil { log.Warning(err.Error()) } @@ -186,20 +172,19 @@ func (n *Node) Connect() *Node { } func (n *Node) Disconnect() { - n.quit = true - if n.qClient != nil { - n.qClient.Disconnect() + if n.mqttClient != nil { + n.mqttClient.Disconnect() } } func (n *Node) ping(msg *message.PublishMessage) (err error) { + _ = n.mqttClient.Pong() + _ = json.Unmarshal(msg.Payload(), n.stat) n.lastPing = time.Now() switch n.stat.Status { - case "busy": - n.ConnStatus = "wait" case "enabled": n.ConnStatus = "connected" default: @@ -207,3 +192,7 @@ func (n *Node) ping(msg *message.PublishMessage) (err error) { } return } + +func (n *Node) IsConnected() bool { + return time.Now().Sub(n.lastPing).Seconds() < 2 +} diff --git a/system/core/node_bind.go b/system/core/node_bind.go index cd33e8fe3..7cf0976a0 100644 --- a/system/core/node_bind.go +++ b/system/core/node_bind.go @@ -18,7 +18,7 @@ type NodeBind struct { //} func (n *NodeBind) IsConnected() bool { - return n.node.IsConnected + return n.node.IsConnected() } func (n *NodeBind) Name() string { diff --git a/system/core/worker.go b/system/core/worker.go index 21e40855f..33a4ba124 100644 --- a/system/core/worker.go +++ b/system/core/worker.go @@ -95,7 +95,7 @@ func (w *Worker) removeActions() { // Run worker script, and send result to flow as message struct func (w *Worker) Do() { - if w.isRuning || !w.flow.Node.IsConnected { + if w.isRuning || !w.flow.Node.IsConnected() { return } diff --git a/system/initial/env1/devices.go b/system/initial/env1/devices.go index cfa7e8726..892fde737 100644 --- a/system/initial/env1/devices.go +++ b/system/initial/env1/devices.go @@ -19,12 +19,12 @@ func devices(node1 *m.Node, device1 := &m.Device{ Name: "device1", Status: "enabled", - Type: DevTypeModbus, + Type: DevTypeModbusRtu, Node: node1, Properties: []byte("{}"), } - modBusConfig := &DevModBusConfig{ + modBusConfig := &DevModBusRtuConfig{ SlaveId: 1, Baud: 19200, DataBits: 8, @@ -405,13 +405,13 @@ func devices(node1 *m.Node, device3 := &m.Device{ Name: "device3", Status: "enabled", - Type: DevTypeModbus, + Type: DevTypeModbusRtu, Node: node1, IsGroup: true, Properties: []byte("{}"), } - modBusConfig = &DevModBusConfig{ + modBusConfig = &DevModBusRtuConfig{ Baud: 115200, DataBits: 8, StopBits: 2, @@ -434,7 +434,7 @@ func devices(node1 *m.Node, device4 := &m.Device{ Name: "device4", Status: "enabled", - Type: DevTypeModbus, + Type: DevTypeModbusRtu, Device: device3, Properties: []byte("{\"slave_id\": 2}"), } diff --git a/system/logging/backend.go b/system/logging/backend.go index 8d42b6e48..8b4680297 100644 --- a/system/logging/backend.go +++ b/system/logging/backend.go @@ -1,7 +1,6 @@ package logging import ( - "github.com/e154/smart-home/adaptors" "github.com/e154/smart-home/common" m "github.com/e154/smart-home/models" "github.com/e154/smart-home/system/config" @@ -11,17 +10,17 @@ import ( ) type LogBackend struct { - L *logrus.Logger - adaptors *adaptors.Adaptors - oldLog *m.Log - logging bool + L *logrus.Logger + dbSaver *LogDbSaver + oldLog *m.Log + logging bool } -func NewLogBackend(logger *logrus.Logger, adaptors *adaptors.Adaptors, conf *config.AppConfig) (back *LogBackend) { +func NewLogBackend(logger *logrus.Logger, dbSaver *LogDbSaver, conf *config.AppConfig) (back *LogBackend) { back = &LogBackend{ - L: logger, - adaptors: adaptors, - logging: conf.Logging, + L: logger, + dbSaver: dbSaver, + logging: conf.Logging, } back.L.Out = os.Stdout return @@ -58,7 +57,6 @@ func (b *LogBackend) Log(level logging.Level, calldepth int, rec *logging.Record logLevel = "Debug" } - //TODO optimise if b.oldLog != nil { if b.oldLog.Body == rec.Message() && b.oldLog.Level == logLevel { return @@ -73,7 +71,7 @@ func (b *LogBackend) Log(level logging.Level, calldepth int, rec *logging.Record b.oldLog = record - _, err = b.adaptors.Log.Add(record) + b.dbSaver.Save(*record) return nil } diff --git a/system/logging/db_saver.go b/system/logging/db_saver.go new file mode 100644 index 000000000..afff9a9da --- /dev/null +++ b/system/logging/db_saver.go @@ -0,0 +1,86 @@ +package logging + +import ( + "github.com/e154/smart-home/adaptors" + m "github.com/e154/smart-home/models" + "github.com/e154/smart-home/system/graceful_service" + "time" +) + +type LogDbSaver struct { + adaptors *adaptors.Adaptors + isStarted bool + pool chan m.Log + quit chan struct{} +} + +func NewLogDbSaver(adaptors *adaptors.Adaptors, + graceful *graceful_service.GracefulService, ) *LogDbSaver { + saver := &LogDbSaver{ + adaptors: adaptors, + pool: make(chan m.Log), + quit: make(chan struct{}), + } + + graceful.Subscribe(saver) + + saver.Start() + + return saver +} + +func (l *LogDbSaver) Start() { + + if l.isStarted { + return + } + + go func() { + + logList := make([]*m.Log, 0, 50) + ticker := time.NewTicker(time.Second * 5) + defer func() { + ticker.Stop() + }() + + update := func() { + _ = l.adaptors.Log.AddMultiple(logList) + logList = make([]*m.Log, 0, 50) + } + + for { + select { + case <-ticker.C: + if len(logList) > 0 { + update() + } + case logMsg := <-l.pool: + logList = append(logList, &logMsg) + if len(logList) >= 50 { + update() + } + case <-l.quit: + return + } + } + }() + + l.isStarted = true +} + +func (l *LogDbSaver) Shutdown() { + if !l.isStarted { + return + } + l.isStarted = false + l.quit <- struct{}{} + close(l.quit) + close(l.pool) +} + +func (l *LogDbSaver) Save(log m.Log) { + if !l.isStarted { + return + } + l.pool <- log +} diff --git a/system/mqtt/mqtt_client.go b/system/mqtt/mqtt_client.go index e6670fa2e..69b667297 100644 --- a/system/mqtt/mqtt_client.go +++ b/system/mqtt/mqtt_client.go @@ -95,3 +95,22 @@ func (c *Client) Publish(v []byte) (err error) { return } + + +func (c *Client) Pong() (err error) { + + // Creates a new PUBLISH message with the appropriate contents for publishing + pubmsg := message.NewPublishMessage() + if err = pubmsg.SetTopic([]byte(c.topic + "/pong")); err != nil { + return + } + pubmsg.SetPayload([]byte("pong")) + if err = pubmsg.SetQoS(c.qos); err != nil { + return + } + + // Publishes to the server by sending the message + c.client.Publish(pubmsg, nil) + + return +} diff --git a/system/notify/notify.go b/system/notify/notify.go index ac4a24b2e..36dd04f77 100644 --- a/system/notify/notify.go +++ b/system/notify/notify.go @@ -201,11 +201,27 @@ func (n *Notify) read() { } } +func (n *Notify) getCfg() { + + v, err := n.adaptor.Variable.GetByName(notifyVarName) + if err != nil { + log.Error(err.Error()) + return + } + + n.cfg = &NotifyConfig{} + if err = json.Unmarshal([]byte(v.Value), n.cfg); err != nil { + log.Error(err.Error()) + } +} + func (n *Notify) GetCfg() *NotifyConfig { return n.cfg } func (n *Notify) UpdateCfg(cfg *NotifyConfig) error { + cfg.adaptor = n.adaptor + n.cfg = cfg return n.cfg.Update() } diff --git a/system/telegram/telegram.go b/system/telegram/telegram.go index 4b87de1cc..365248ac6 100644 --- a/system/telegram/telegram.go +++ b/system/telegram/telegram.go @@ -72,7 +72,7 @@ func (c *Telegram) start() { chatID := update.Message.Chat.ID text := update.Message.Text - if c.chatId == nil { + if c.chatId == nil || common.Int64Value(c.chatId) == 0 { c.chatId = common.Int64(chatID) if c.updateChatId != nil { c.updateChatId(chatID) @@ -120,7 +120,7 @@ func (c *Telegram) SendMsg(body string) error { return errors.New("bot not started") } - if c.chatId != nil { + if c.chatId != nil && common.Int64Value(c.chatId) != 0 { msg := tgbotapi.NewMessage(common.Int64Value(c.chatId), body) _, err := c.bot.Send(msg) return err diff --git a/tests/models/container.go b/tests/models/container.go index 8b83ba412..78db9777c 100644 --- a/tests/models/container.go +++ b/tests/models/container.go @@ -64,6 +64,7 @@ func BuildContainer() (container *dig.Container) { container.Provide(stream.NewHub) container.Provide(telemetry.NewTelemetry) container.Provide(logging.NewLogBackend) + container.Provide(logging.NewLogDbSaver) container.Provide(endpoint.NewEndpoint) container.Provide(gate_client.NewGateClient) container.Provide(notify.NewNotify) diff --git a/tests/scripts/container.go b/tests/scripts/container.go index 4cd1ab466..f6f458784 100644 --- a/tests/scripts/container.go +++ b/tests/scripts/container.go @@ -59,6 +59,7 @@ func BuildContainer() (container *dig.Container) { container.Provide(stream.NewHub) container.Provide(telemetry.NewTelemetry) container.Provide(logging.NewLogBackend) + container.Provide(logging.NewLogDbSaver) container.Provide(gate_client.NewGateClient) container.Provide(notify.NewNotify) diff --git a/tests/workflow/container.go b/tests/workflow/container.go index 43d168e70..d12421759 100644 --- a/tests/workflow/container.go +++ b/tests/workflow/container.go @@ -64,6 +64,7 @@ func BuildContainer() (container *dig.Container) { container.Provide(stream.NewHub) container.Provide(telemetry.NewTelemetry) container.Provide(logging.NewLogBackend) + container.Provide(logging.NewLogDbSaver) container.Provide(endpoint.NewEndpoint) container.Provide(gate_client.NewGateClient) container.Provide(notify.NewNotify)