Skip to content

Commit

Permalink
Merge PR #745: New plugin: ESP Somfy RTS
Browse files Browse the repository at this point in the history
  • Loading branch information
jenkins committed Nov 27, 2024
2 parents a35312b + 346657e commit c76ebaf
Show file tree
Hide file tree
Showing 15 changed files with 1,528 additions and 0 deletions.
9 changes: 9 additions & 0 deletions debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,15 @@ Description: nymea integration plugin for ESPuino
This package contains the nymea integration plugin for ESPuino devices.


Package: nymea-plugin-espsomfyrts
Architecture: any
Depends: ${shlibs:Depends},
${misc:Depends},
Conflicts: nymea-plugins-translations (<< 1.0.1)
Description: nymea integration plugin for ESP-Somfy-RTS
This package contains the nymea integration plugin for the ESP Somfy RTS project.


Package: nymea-plugin-evbox
Architecture: any
Depends: ${shlibs:Depends},
Expand Down
2 changes: 2 additions & 0 deletions debian/nymea-plugin-espsomfyrts.install.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginespsomfyrts.so
espsomfyrts/translations/*qm usr/share/nymea/translations/
7 changes: 7 additions & 0 deletions espsomfyrts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# ESPSomfy-RTS

This integration adds support for Somfy RTS devices using the ESPSomfy-RTS project.

For more information about the project and how to build your own somfy controller under 12$ have look on the project page.

https://github.com/rstrouse/ESPSomfy-RTS
Binary file added espsomfyrts/espsomfy-rts.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
249 changes: 249 additions & 0 deletions espsomfyrts/espsomfyrts.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2024, nymea GmbH
* Contact: [email protected]
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* [email protected] or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "espsomfyrts.h"
#include "extern-plugininfo.h"

#include <network/networkdevicemonitor.h>

#include <QJsonDocument>
#include <QJsonParseError>

EspSomfyRts::EspSomfyRts(NetworkDeviceMonitor *monitor, QObject *parent)
: QObject{parent},
m_monitor{monitor}
{
m_websocketUrl.setScheme("ws");
m_websocketUrl.setHost("127.0.0.1");
m_websocketUrl.setPort(8080);

m_webSocket = new QWebSocket("nymea", QWebSocketProtocol::Version13, this);
connect(m_webSocket, &QWebSocket::textMessageReceived, this, &EspSomfyRts::onWebSocketTextMessageReceived);
connect(m_webSocket, &QWebSocket::connected, this, [this](){
qCDebug(dcESPSomfyRTS()) << "Websocket connected";
m_connected = true;
emit connectedChanged(m_connected);
});

connect(m_webSocket, &QWebSocket::disconnected, this, [this](){
qCDebug(dcESPSomfyRTS()) << "Websocket disconnected";
m_connected = false;
emit connectedChanged(m_connected);

m_reconnectTimer.start();
});

if (m_monitor) {
qCDebug(dcESPSomfyRTS()) << "Setting up ESP Somfy using the network device monitor on" << m_monitor->macAddress();
connect(m_monitor, &NetworkDeviceMonitor::reachableChanged, this, &EspSomfyRts::onMonitorReachableChanged);

// Init connection based on the monitor
onMonitorReachableChanged(m_monitor->reachable());
}

// Websocket reconnect mechanism
m_reconnectTimer.setInterval(5);
m_reconnectTimer.setSingleShot(false);
connect(&m_reconnectTimer, &QTimer::timeout, this, [this](){
if (m_webSocket->state() == QAbstractSocket::UnconnectedState && m_monitor->reachable()) {
m_websocketUrl.setHost(m_monitor->networkDeviceInfo().address().toString());
qCDebug(dcESPSomfyRTS()) << "Trying to connect to" << m_websocketUrl;
m_webSocket->open(m_websocketUrl);
}
});
}

QHostAddress EspSomfyRts::address() const
{
return QHostAddress(m_websocketUrl.host());
}

bool EspSomfyRts::connected() const
{
return m_connected;
}

QString EspSomfyRts::firmwareVersion() const
{
return m_firmwareVersion;
}

QUrl EspSomfyRts::shadesUrl()
{
return buildUrl("shades");
}

QUrl EspSomfyRts::shadeCommandUrl()
{
return buildUrl("shadeCommand");
}

QUrl EspSomfyRts::tiltCommandUrl()
{
return buildUrl("tiltCommand");
}

QString EspSomfyRts::getShadeCommandString(ShadeCommand shadeCommand)
{
QString shadeCommandString;

switch(shadeCommand) {
case ShadeCommandMy:
shadeCommandString = "m";
break;
case ShadeCommandUp:
shadeCommandString = "u";
break;
case ShadeCommandDown:
shadeCommandString = "d";
break;
case ShadeCommandMyUp:
shadeCommandString = "mu";
break;
case ShadeCommandMyDown:
shadeCommandString = "md";
break;
case ShadeCommandUpDown:
shadeCommandString = "ud";
break;
case ShadeCommandMyUpDown:
shadeCommandString = "mud";
break;
case ShadeCommandProg:
shadeCommandString = "p";
break;
case ShadeCommandSunFlag:
shadeCommandString = "s";
break;
case ShadeCommandFlag:
shadeCommandString = "f";
break;
case ShadeCommandStepUp:
shadeCommandString = "su";
break;
case ShadeCommandStepDown:
shadeCommandString = "sd";
break;
case ShadeCommandFavorite:
shadeCommandString = "fav";
break;
case ShadeCommandStop:
shadeCommandString = "stop";
break;
}

return shadeCommandString;
}

void EspSomfyRts::onMonitorReachableChanged(bool reachable)
{
qCDebug(dcESPSomfyRTS()) << "Network device of" << m_websocketUrl.host() << "is" << (reachable ? "now reachable" : "not reachable any more");

if (reachable) {
if (m_webSocket->state() == QAbstractSocket::ConnectedState)
return;

m_websocketUrl.setHost(m_monitor->networkDeviceInfo().address().toString());
qCDebug(dcESPSomfyRTS()) << "Connecting to" << m_websocketUrl.toString();
m_webSocket->open(m_websocketUrl);
}
}

void EspSomfyRts::onWebSocketTextMessageReceived(const QString &message)
{
//qCDebug(dcESPSomfyRTS()) << "Websocket message received:" << message;

if (message.startsWith("42")) {
QJsonParseError jsonError;
QByteArray rawMessage = message.mid(3, message.size() - 4).toUtf8();
// Make parsing easier
int index = rawMessage.indexOf(',');
if (index < 0) {
qCWarning(dcESPSomfyRTS()) << "Could not parse notification from data" << rawMessage;
return;
}

QString notification = rawMessage.left(index);
QByteArray rawPayload = rawMessage.right(rawMessage.size() - index - 1);

QJsonDocument jsonDoc = QJsonDocument::fromJson(rawPayload, &jsonError);
if (jsonError.error != QJsonParseError::NoError) {
qCWarning(dcESPSomfyRTS()) << "Json error parsing the data" << rawPayload << jsonError.error << jsonError.errorString();
return;
}

QVariantMap payload = jsonDoc.toVariant().toMap();

if (notification == "wifiStrength") {

uint signalStrength = 0;
int dbm = payload.value("strength").toInt();
if (dbm > -90)
signalStrength += 20;
if (dbm > -80)
signalStrength += 20;
if (dbm > -70)
signalStrength += 20;
if (dbm > -67)
signalStrength += 20;
if (dbm > -30)
signalStrength += 20;

if (m_signalStrength != signalStrength) {
m_signalStrength = signalStrength;
emit signalStrengthChanged(m_signalStrength);
}

} else if (notification == "fwStatus") {

QString firmwareVersion = payload.value("fwVersion").toMap().value("name").toString();
if (m_firmwareVersion != firmwareVersion) {
m_firmwareVersion = firmwareVersion;
emit firmwareVersionChanged(m_firmwareVersion);
}

// TODO. firmware update

} else if (notification == "shadeState") {
emit shadeStateReceived(payload);
} else if (notification == "memStatus") {
// We are not interested in this, filter it out
} else {
qCDebug(dcESPSomfyRTS()) << "Notification" << notification << qUtf8Printable(jsonDoc.toJson(QJsonDocument::Indented));
}

}
}

QUrl EspSomfyRts::buildUrl(const QString &path)
{
return QUrl(QString("http://%1/%2").arg(m_websocketUrl.host()).arg(path));
}

Loading

0 comments on commit c76ebaf

Please sign in to comment.