Merge PR #151: New plugin: One-Wire

This commit is contained in:
Jenkins 2019-09-19 12:28:00 +02:00
commit e98ac4fee5
10 changed files with 1145 additions and 0 deletions

18
debian/control vendored
View File

@ -13,6 +13,7 @@ Build-depends: libboblight-dev,
python:any,
qtbase5-dev,
qtconnectivity5-dev,
libow-dev,
Standards-Version: 3.9.3
@ -420,6 +421,22 @@ Description: nymea.io plugin for networkdetector
This package will install the nymea.io plugin for networkdetector
Package: nymea-plugin-onewire
Architecture: any
Depends: ${shlibs:Depends},
${misc:Depends},
nymea-plugins-translations,
Description: nymea.io plugin for one wire devices
The nymea daemon is a plugin based IoT (Internet of Things) server. The
server works like a translator for devices, things and services and
allows them to interact.
With the powerful rule engine you are able to connect any device available
in the system and create individual scenes and behaviors for your environment.
.
This package will install the nymea.io plugin for one wire devices
Package: nymea-plugin-openweathermap
Architecture: any
Depends: ${shlibs:Depends},
@ -833,6 +850,7 @@ Depends: nymea-plugin-boblight,
nymea-plugin-unipi,
nymea-plugin-serialportcommander,
nymea-plugin-systemmonitor,
nymea-plugin-onewire,
Replaces: guh-plugins-maker
Description: Plugins for nymea IoT server - Meta package for makers, tinkers and hackers
The nymea daemon is a plugin based IoT (Internet of Things) server. The

View File

@ -0,0 +1 @@
usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_devicepluginonewire.so

View File

@ -29,6 +29,7 @@ PLUGIN_DIRS = \
mqttclient \
netatmo \
networkdetector \
onewire \
openweathermap \
osdomotics \
philipshue \

39
onewire/README.md Normal file
View File

@ -0,0 +1,39 @@
# One wire
This plugin allows to add one wire devices through the one wire file system.
## One wire interface device
This device initializes OWFS, during the device setup you can set OWFS init arguments.
Default arguments are "--i2c=ALL:ALL" to scan for one-wire devices on all I2C interfaces.
You can simulate one-wire device with following init argument: "--fake=10,22,28,05"
More about init arguments here: https://www.owfs.org
## Supported one-wire devices
* Family Code 10 - Temperature Sensors
..* DS18S20
..* DS1820
..* DS18S20-PAR
..* DS1920
* Family Code 22 - Temperature Sensors
..* DS1822
..* DS1822-PAR
* Family Code 28 - Temperature Sensors
..* DS18B20
..* DS18B20-PAR
..* DS18B20X
* Family Code 3B - Temperature Sensors
..* DS1825
* Family Code 05 - Single channel switch
..* DS2405
* Family Code 12 - Dual channel switch
..* DS2406
..* DS2407
* Family Code 3A - Dual channel switch
..* DS2413
* Family Code 29 - Eight channel switch
..* DS2408

View File

@ -0,0 +1,374 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Bernhard Trinnes <bernhard.trinnes@nymea.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "devicepluginonewire.h"
#include "devices/device.h"
#include "plugininfo.h"
#include <QDebug>
#include <QDir>
DevicePluginOneWire::DevicePluginOneWire()
{
}
Device::DeviceError DevicePluginOneWire::discoverDevices(const DeviceClassId &deviceClassId, const ParamList &params)
{
Q_UNUSED(params);
if (deviceClassId == temperatureSensorDeviceClassId ||
deviceClassId == singleChannelSwitchDeviceClassId ||
deviceClassId == dualChannelSwitchDeviceClassId ||
deviceClassId == eightChannelSwitchDeviceClassId) {
if (myDevices().filterByDeviceClassId(oneWireInterfaceDeviceClassId).isEmpty()) {
//No one wire interface intitialized
return Device::DeviceErrorHardwareNotAvailable;
}
foreach(Device *parentDevice, myDevices().filterByDeviceClassId(oneWireInterfaceDeviceClassId)) {
if (parentDevice->stateValue(oneWireInterfaceAutoAddStateTypeId).toBool()) {
//devices cannot be discovered since auto mode is enabled
return Device::DeviceErrorNoError;
} else {
if (m_oneWireInterface)
m_oneWireInterface->discoverDevices();
}
}
return Device::DeviceErrorAsync;
}
return Device::DeviceErrorDeviceClassNotFound;
}
Device::DeviceSetupStatus DevicePluginOneWire::setupDevice(Device *device)
{
if (device->deviceClassId() == oneWireInterfaceDeviceClassId) {
qCDebug(dcOneWire) << "Setup one wire interface";
if (m_oneWireInterface) {
qCWarning(dcOneWire) << "One wire interface already set up";
return Device::DeviceSetupStatusFailure;
}
m_oneWireInterface = new OneWire(this);
QByteArray initArguments = device->paramValue(oneWireInterfaceDeviceInitArgsParamTypeId).toByteArray();
if (!m_oneWireInterface->init(initArguments)){
m_oneWireInterface->deleteLater();
m_oneWireInterface = nullptr;
return Device::DeviceSetupStatusFailure;
}
connect(m_oneWireInterface, &OneWire::devicesDiscovered, this, &DevicePluginOneWire::onOneWireDevicesDiscovered);
return Device::DeviceSetupStatusSuccess;
}
if (device->deviceClassId() == temperatureSensorDeviceClassId) {
qCDebug(dcOneWire) << "Setup one wire temperature sensor" << device->params();
if (!m_oneWireInterface) { //in case the child was setup before the interface
double temperature = m_oneWireInterface->getTemperature(device->paramValue(temperatureSensorDeviceAddressParamTypeId).toByteArray());
device->setStateValue(temperatureSensorTemperatureStateTypeId, temperature);
}
return Device::DeviceSetupStatusSuccess;
}
if (device->deviceClassId() == singleChannelSwitchDeviceClassId) {
qCDebug(dcOneWire) << "Setup one wire switch" << device->params();
if (!m_oneWireInterface) {
QByteArray address = device->paramValue(singleChannelSwitchDeviceAddressParamTypeId).toByteArray();
device->setStateValue(singleChannelSwitchDigitalOutputStateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_A));
}
return Device::DeviceSetupStatusSuccess;
}
if (device->deviceClassId() == dualChannelSwitchDeviceClassId) {
qCDebug(dcOneWire) << "Setup one wire dual switch" << device->params();
if (!m_oneWireInterface) {
QByteArray address = device->paramValue(dualChannelSwitchDeviceAddressParamTypeId).toByteArray();
device->setStateValue(dualChannelSwitchDigitalOutput1StateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_A));
device->setStateValue(dualChannelSwitchDigitalOutput2StateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_B));
}
return Device::DeviceSetupStatusSuccess;
}
if (device->deviceClassId() == eightChannelSwitchDeviceClassId) {
qCDebug(dcOneWire) << "Setup one wire eight channel switch" << device->params();
if (!m_oneWireInterface) {
QByteArray address = device->paramValue(eightChannelSwitchDeviceAddressParamTypeId).toByteArray();
device->setStateValue(eightChannelSwitchDigitalOutput1StateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_A));
device->setStateValue(eightChannelSwitchDigitalOutput2StateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_B));
device->setStateValue(eightChannelSwitchDigitalOutput3StateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_C));
device->setStateValue(eightChannelSwitchDigitalOutput4StateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_D));
device->setStateValue(eightChannelSwitchDigitalOutput5StateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_E));
device->setStateValue(eightChannelSwitchDigitalOutput6StateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_F));
device->setStateValue(eightChannelSwitchDigitalOutput7StateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_G));
device->setStateValue(eightChannelSwitchDigitalOutput8StateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_H));
}
return Device::DeviceSetupStatusSuccess;
}
return Device::DeviceSetupStatusFailure;
}
void DevicePluginOneWire::postSetupDevice(Device *device)
{
Q_UNUSED(device);
if(!m_pluginTimer) {
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(10);
connect(m_pluginTimer, &PluginTimer::timeout, this, &DevicePluginOneWire::onPluginTimer);
}
}
Device::DeviceError DevicePluginOneWire::executeAction(Device *device, const Action &action)
{
if (device->deviceClassId() == oneWireInterfaceDeviceClassId) {
if (action.actionTypeId() == oneWireInterfaceAutoAddActionTypeId){
device->setStateValue(oneWireInterfaceAutoAddStateTypeId, action.param(oneWireInterfaceAutoAddActionAutoAddParamTypeId).value());
return Device::DeviceErrorNoError;
}
return Device::DeviceErrorActionTypeNotFound;
}
if (device->deviceClassId() == singleChannelSwitchDeviceClassId) {
if (action.actionTypeId() == singleChannelSwitchDigitalOutputActionTypeId){
m_oneWireInterface->setSwitchOutput(device->paramValue(singleChannelSwitchDeviceAddressParamTypeId).toByteArray(), OneWire::SwitchChannel::PIO_A, action.param(singleChannelSwitchDigitalOutputActionDigitalOutputParamTypeId).value().toBool());
return Device::DeviceErrorNoError;
}
return Device::DeviceErrorActionTypeNotFound;
}
if (device->deviceClassId() == dualChannelSwitchDeviceClassId) {
if (action.actionTypeId() == dualChannelSwitchDigitalOutput1ActionTypeId){
m_oneWireInterface->setSwitchOutput(device->paramValue(dualChannelSwitchDeviceAddressParamTypeId).toByteArray(), OneWire::SwitchChannel::PIO_A, action.param(dualChannelSwitchDigitalOutput1ActionDigitalOutput1ParamTypeId).value().toBool());
return Device::DeviceErrorNoError;
}
if (action.actionTypeId() == dualChannelSwitchDigitalOutput2ActionTypeId){
m_oneWireInterface->setSwitchOutput(device->paramValue(dualChannelSwitchDeviceAddressParamTypeId).toByteArray(), OneWire::SwitchChannel::PIO_B, action.param(dualChannelSwitchDigitalOutput2ActionDigitalOutput2ParamTypeId).value().toBool());
return Device::DeviceErrorNoError;
}
return Device::DeviceErrorActionTypeNotFound;
}
if (device->deviceClassId() == eightChannelSwitchDeviceClassId) {
if (action.actionTypeId() == eightChannelSwitchDigitalOutput1ActionTypeId){
m_oneWireInterface->setSwitchOutput(device->paramValue(eightChannelSwitchDeviceAddressParamTypeId).toByteArray(), OneWire::SwitchChannel::PIO_A, action.param(eightChannelSwitchDigitalOutput1ActionDigitalOutput1ParamTypeId).value().toBool());
return Device::DeviceErrorNoError;
}
if (action.actionTypeId() == eightChannelSwitchDigitalOutput2ActionTypeId){
m_oneWireInterface->setSwitchOutput(device->paramValue(eightChannelSwitchDeviceAddressParamTypeId).toByteArray(), OneWire::SwitchChannel::PIO_B, action.param(eightChannelSwitchDigitalOutput2ActionDigitalOutput2ParamTypeId).value().toBool());
return Device::DeviceErrorNoError;
}
if (action.actionTypeId() == eightChannelSwitchDigitalOutput3ActionTypeId){
m_oneWireInterface->setSwitchOutput(device->paramValue(eightChannelSwitchDeviceAddressParamTypeId).toByteArray(), OneWire::SwitchChannel::PIO_C, action.param(eightChannelSwitchDigitalOutput3ActionDigitalOutput3ParamTypeId).value().toBool());
return Device::DeviceErrorNoError;
}
if (action.actionTypeId() == eightChannelSwitchDigitalOutput4ActionTypeId){
m_oneWireInterface->setSwitchOutput(device->paramValue(eightChannelSwitchDeviceAddressParamTypeId).toByteArray(), OneWire::SwitchChannel::PIO_D, action.param(eightChannelSwitchDigitalOutput4ActionDigitalOutput4ParamTypeId).value().toBool());
return Device::DeviceErrorNoError;
}
if (action.actionTypeId() == eightChannelSwitchDigitalOutput5ActionTypeId){
m_oneWireInterface->setSwitchOutput(device->paramValue(eightChannelSwitchDeviceAddressParamTypeId).toByteArray(), OneWire::SwitchChannel::PIO_E, action.param(eightChannelSwitchDigitalOutput5ActionDigitalOutput5ParamTypeId).value().toBool());
return Device::DeviceErrorNoError;
}
if (action.actionTypeId() == eightChannelSwitchDigitalOutput6ActionTypeId){
m_oneWireInterface->setSwitchOutput(device->paramValue(eightChannelSwitchDeviceAddressParamTypeId).toByteArray(), OneWire::SwitchChannel::PIO_F, action.param(eightChannelSwitchDigitalOutput6ActionDigitalOutput6ParamTypeId).value().toBool());
return Device::DeviceErrorNoError;
}
if (action.actionTypeId() == eightChannelSwitchDigitalOutput7ActionTypeId){
m_oneWireInterface->setSwitchOutput(device->paramValue(eightChannelSwitchDeviceAddressParamTypeId).toByteArray(), OneWire::SwitchChannel::PIO_G, action.param(eightChannelSwitchDigitalOutput7ActionDigitalOutput7ParamTypeId).value().toBool());
return Device::DeviceErrorNoError;
}
if (action.actionTypeId() == eightChannelSwitchDigitalOutput8ActionTypeId){
m_oneWireInterface->setSwitchOutput(device->paramValue(eightChannelSwitchDeviceAddressParamTypeId).toByteArray(), OneWire::SwitchChannel::PIO_H, action.param(eightChannelSwitchDigitalOutput8ActionDigitalOutput8ParamTypeId).value().toBool());
return Device::DeviceErrorNoError;
}
return Device::DeviceErrorActionTypeNotFound;
}
return Device::DeviceErrorNoError;
}
void DevicePluginOneWire::deviceRemoved(Device *device)
{
if (device->deviceClassId() == oneWireInterfaceDeviceClassId) {
m_oneWireInterface->deleteLater();
m_oneWireInterface = nullptr;
return;
}
if (myDevices().empty()) {
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
m_pluginTimer = nullptr;
}
}
void DevicePluginOneWire::onPluginTimer()
{
foreach (Device *device, myDevices()) {
if (device->deviceClassId() == oneWireInterfaceDeviceClassId) {
device->setStateValue(oneWireInterfaceConnectedStateTypeId, m_oneWireInterface->interfaceIsAvailable());
if (device->stateValue(oneWireInterfaceAutoAddStateTypeId).toBool()) {
m_oneWireInterface->discoverDevices();
}
}
if (device->deviceClassId() == temperatureSensorDeviceClassId) {
QByteArray address = device->paramValue(temperatureSensorDeviceAddressParamTypeId).toByteArray();
double temperature = m_oneWireInterface->getTemperature(address);
device->setStateValue(temperatureSensorTemperatureStateTypeId, temperature);
}
if (device->deviceClassId() == singleChannelSwitchDeviceClassId) {
QByteArray address = device->paramValue(singleChannelSwitchDeviceAddressParamTypeId).toByteArray();
device->setStateValue(singleChannelSwitchDigitalOutputStateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_A));
}
if (device->deviceClassId() == dualChannelSwitchDeviceClassId) {
QByteArray address = device->paramValue(dualChannelSwitchDeviceAddressParamTypeId).toByteArray();
device->setStateValue(dualChannelSwitchDigitalOutput1StateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_A));
device->setStateValue(dualChannelSwitchDigitalOutput2StateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_B));
}
if (device->deviceClassId() == eightChannelSwitchDeviceClassId) {
QByteArray address = device->paramValue(eightChannelSwitchDeviceAddressParamTypeId).toByteArray();
device->setStateValue(eightChannelSwitchDigitalOutput1StateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_A));
device->setStateValue(eightChannelSwitchDigitalOutput2StateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_B));
device->setStateValue(eightChannelSwitchDigitalOutput3StateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_C));
device->setStateValue(eightChannelSwitchDigitalOutput4StateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_D));
device->setStateValue(eightChannelSwitchDigitalOutput5StateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_E));
device->setStateValue(eightChannelSwitchDigitalOutput6StateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_F));
device->setStateValue(eightChannelSwitchDigitalOutput7StateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_G));
device->setStateValue(eightChannelSwitchDigitalOutput8StateTypeId, m_oneWireInterface->getSwitchOutput(address, OneWire::SwitchChannel::PIO_H));
}
}
}
void DevicePluginOneWire::onOneWireDevicesDiscovered(QList<OneWire::OneWireDevice> oneWireDevices)
{
foreach(Device *parentDevice, myDevices().filterByDeviceClassId(oneWireInterfaceDeviceClassId)) {
bool autoDiscoverEnabled = parentDevice->stateValue(oneWireInterfaceAutoAddStateTypeId).toBool();
QList<DeviceDescriptor> temperatureDeviceDescriptors;
QList<DeviceDescriptor> singleChannelSwitchDeviceDescriptors;
QList<DeviceDescriptor> dualChannelSwitchDeviceDescriptors;
QList<DeviceDescriptor> eightChannelSwitchDeviceDescriptors;
foreach (OneWire::OneWireDevice oneWireDevice, oneWireDevices){
switch (oneWireDevice.family) {
//https://github.com/owfs/owfs-doc/wiki/1Wire-Device-List
case 0x10: //DS18S20
case 0x22: //DS1822
case 0x28: //DS18B20
case 0x3b: {//DS1825, MAX31826, MAX31850
DeviceDescriptor descriptor(temperatureSensorDeviceClassId, oneWireDevice.type, "One wire temperature sensor", parentDevice->id());
ParamList params;
params.append(Param(temperatureSensorDeviceAddressParamTypeId, oneWireDevice.address));
params.append(Param(temperatureSensorDeviceTypeParamTypeId, oneWireDevice.type));
foreach (Device *existingDevice, myDevices().filterByDeviceClassId(temperatureSensorDeviceClassId)){
if (existingDevice->paramValue(temperatureSensorDeviceAddressParamTypeId).toString() == oneWireDevice.address) {
descriptor.setDeviceId(existingDevice->id());
break;
}
}
descriptor.setParams(params);
temperatureDeviceDescriptors.append(descriptor);
break;
}
case 0x05: { //single channel switch
DeviceDescriptor descriptor(singleChannelSwitchDeviceClassId, oneWireDevice.type, "One wire single channel switch", parentDevice->id());
ParamList params;
params.append(Param(singleChannelSwitchDeviceAddressParamTypeId, oneWireDevice.address));
params.append(Param(singleChannelSwitchDeviceTypeParamTypeId, oneWireDevice.type));
foreach (Device *existingDevice, myDevices().filterByDeviceClassId(singleChannelSwitchDeviceClassId)){
if (existingDevice->paramValue(singleChannelSwitchDeviceAddressParamTypeId).toString() == oneWireDevice.address) {
descriptor.setDeviceId(existingDevice->id());
break;
}
}
descriptor.setParams(params);
singleChannelSwitchDeviceDescriptors.append(descriptor);
break;
}
case 0x12:
case 0x3a: {//dual channel switch
DeviceDescriptor descriptor(dualChannelSwitchDeviceClassId, oneWireDevice.type, "One wire dual channel switch", parentDevice->id());
ParamList params;
params.append(Param(dualChannelSwitchDeviceAddressParamTypeId, oneWireDevice.address));
params.append(Param(dualChannelSwitchDeviceTypeParamTypeId, oneWireDevice.type));
foreach (Device *existingDevice, myDevices().filterByDeviceClassId(dualChannelSwitchDeviceClassId)){
if (existingDevice->paramValue(dualChannelSwitchDeviceAddressParamTypeId).toString() == oneWireDevice.address) {
descriptor.setDeviceId(existingDevice->id());
break;
}
}
descriptor.setParams(params);
dualChannelSwitchDeviceDescriptors.append(descriptor);
break;
}
case 0x29: { //eight channel switch
DeviceDescriptor descriptor(eightChannelSwitchDeviceClassId, oneWireDevice.type, "One wire eight channel switch", parentDevice->id());
ParamList params;
params.append(Param(eightChannelSwitchDeviceAddressParamTypeId, oneWireDevice.address));
params.append(Param(eightChannelSwitchDeviceTypeParamTypeId, oneWireDevice.type));
foreach (Device *existingDevice, myDevices().filterByDeviceClassId(eightChannelSwitchDeviceClassId)){
if (existingDevice->paramValue(eightChannelSwitchDeviceAddressParamTypeId).toString() == oneWireDevice.address) {
descriptor.setDeviceId(existingDevice->id());
break;
}
}
descriptor.setParams(params);
eightChannelSwitchDeviceDescriptors.append(descriptor);
break;
}
default:
qDebug(dcOneWire()) << "Unknown Device discovered" << oneWireDevice.type << oneWireDevice.address;
break;
}
}
if (autoDiscoverEnabled) {
if (!temperatureDeviceDescriptors.isEmpty())
emit autoDevicesAppeared(temperatureSensorDeviceClassId, temperatureDeviceDescriptors);
if (!singleChannelSwitchDeviceDescriptors.isEmpty())
emit autoDevicesAppeared(singleChannelSwitchDeviceClassId, singleChannelSwitchDeviceDescriptors);
if (!dualChannelSwitchDeviceDescriptors.isEmpty())
emit autoDevicesAppeared(dualChannelSwitchDeviceClassId, dualChannelSwitchDeviceDescriptors);
if (!eightChannelSwitchDeviceDescriptors.isEmpty())
emit autoDevicesAppeared(eightChannelSwitchDeviceClassId, eightChannelSwitchDeviceDescriptors);
} else {
if (!temperatureDeviceDescriptors.isEmpty())
emit devicesDiscovered(temperatureSensorDeviceClassId, temperatureDeviceDescriptors);
if (!singleChannelSwitchDeviceDescriptors.isEmpty())
emit devicesDiscovered(singleChannelSwitchDeviceClassId, singleChannelSwitchDeviceDescriptors);
if (!dualChannelSwitchDeviceDescriptors.isEmpty())
emit devicesDiscovered(dualChannelSwitchDeviceClassId, dualChannelSwitchDeviceDescriptors);
if (!eightChannelSwitchDeviceDescriptors.isEmpty())
emit devicesDiscovered(eightChannelSwitchDeviceClassId, eightChannelSwitchDeviceDescriptors);
}
break;
}
}

View File

@ -0,0 +1,56 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Bernhard Trinnes <bernhard.trinnes@guh.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef DEVICEPLUGINONEWIRE_H
#define DEVICEPLUGINONEWIRE_H
#include "plugintimer.h"
#include "devices/deviceplugin.h"
#include "onewire.h"
#include <QHash>
class DevicePluginOneWire : public DevicePlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "io.nymea.DevicePlugin" FILE "devicepluginonewire.json")
Q_INTERFACES(DevicePlugin)
public:
explicit DevicePluginOneWire();
Device::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList &params) override;
Device::DeviceSetupStatus setupDevice(Device *device) override;
void postSetupDevice(Device *device) override;
Device::DeviceError executeAction(Device *device, const Action &action) override;
void deviceRemoved(Device *device) override;
private:
PluginTimer *m_pluginTimer = nullptr;
OneWire *m_oneWireInterface = nullptr;
private slots:
void onPluginTimer();
void onOneWireDevicesDiscovered(QList<OneWire::OneWireDevice> devices);
};
#endif // DEVICEPLUGINONEWIRE_H

View File

@ -0,0 +1,274 @@
{
"displayName": "One Wire",
"name": "OneWire",
"id": "2c697fb7-0645-466d-9cb9-aa1922c85bee",
"vendors": [
{
"displayName": "One wire",
"name": "oneWire",
"id": "cecc5fae-29cf-40c0-b1f8-0af2dc8e8a63",
"deviceClasses": [
{
"id": "c36c68d9-6182-4ae1-972d-b8b5e0cf185f",
"name": "oneWireInterface",
"displayName": "One wire interface",
"interfaces": ["gateway"],
"createMethods": ["user"],
"paramTypes": [
{
"id": "a0e773ff-fd19-499e-96f0-830168229cd3",
"name": "initArgs",
"displayName": "OWFS init arguments",
"type": "QString",
"defaultValue": "--i2c=ALL:ALL"
}
],
"stateTypes": [
{
"id": "d0ded173-c382-4ee3-8e24-3647b4e16afa",
"name": "connected",
"displayName": "connected",
"displayNameEvent": "connected changed",
"defaultValue": false,
"type": "bool"
},
{
"id": "64baf50e-8ed4-4526-8b92-7e4662d6fa39",
"name": "autoAdd",
"displayName": "Auto add one wire devices",
"displayNameAction": "Set auto add mode",
"displayNameEvent": "Auto add one wire devices changed",
"defaultValue": false,
"type": "bool",
"writable": true
}
]
},
{
"id": "e13beb24-953c-48b3-9262-7cde31d42ef5",
"name": "temperatureSensor",
"displayName": "Temperature Sensor",
"interfaces": ["temperaturesensor"],
"createMethods": ["discovery"],
"paramTypes": [
{
"id": "b4368f34-d9bb-496f-84ba-091bd4b6a332",
"name": "address",
"displayName": "Address",
"type": "QString",
"readOnly": true
},
{
"id": "5005822d-6a32-4bb8-9b77-f79da7382f76",
"name": "type",
"displayName": "Type",
"type": "QString",
"inputType": "TextLine",
"readOnly": true
}
],
"stateTypes": [
{
"id": "b04ee2a5-9b27-4ffc-9e12-7e05f5a41690",
"name": "temperature",
"displayName": "temperature",
"displayNameEvent": "temperature changed",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0
}
]
},
{
"id": "6db42501-5451-4aac-9525-5f886b3188e2",
"name": "singleChannelSwitch",
"displayName": "1-channel switch",
"interfaces": [ ],
"createMethods": ["discovery"],
"paramTypes": [
{
"id": "c9d6b7fd-fa21-473a-b5ed-9c5227749f06",
"name": "address",
"displayName": "Address",
"type": "QString",
"readOnly": true
},
{
"id": "6efc8cb6-81ae-45c0-8910-708401d1ba68",
"name": "type",
"displayName": "Type",
"type": "QString",
"inputType": "TextLine",
"readOnly": true
}
],
"stateTypes": [
{
"id": "ca10a9fd-e4e0-4608-a2d2-6a4ce9644f40",
"name": "digitalOutput",
"displayName": "Digital output",
"displayNameEvent": "Digital output changed",
"displayNameAction": "Set digital output",
"type": "bool",
"defaultValue": false,
"writable": true
}
]
},
{
"id": "023f2b93-61e1-4422-97f5-3d5c14a6628f",
"name": "dualChannelSwitch",
"displayName": "2-channel switch",
"interfaces": [ ],
"createMethods": ["discovery"],
"paramTypes": [
{
"id": "b9a1a23d-1fbf-4849-8aa2-2855e7deaf84",
"name": "address",
"displayName": "Address",
"type": "QString",
"readOnly": true
},
{
"id": "b71ed57b-e768-4119-829e-a0f2c9fa5e18",
"name": "type",
"displayName": "Type",
"type": "QString",
"inputType": "TextLine",
"readOnly": true
}
],
"stateTypes": [
{
"id": "f8b6b4a7-355c-4580-a676-8a4d0d619ff9",
"name": "digitalOutput1",
"displayName": "Digital output 1",
"displayNameEvent": "Digital output 1 changed",
"displayNameAction": "Set digital output 1",
"type": "bool",
"defaultValue": false,
"writable": true
},
{
"id": "82a78aed-5994-4af5-aecb-1806be5de1f3",
"name": "digitalOutput2",
"displayName": "Digital output 2",
"displayNameEvent": "Digital output 2 changed",
"displayNameAction": "Set digital output 2",
"type": "bool",
"defaultValue": false,
"writable": true
}
]
},
{
"id": "71691119-3bda-4424-b853-1a00f21086e1",
"name": "eightChannelSwitch",
"displayName": "8-channel switch",
"interfaces": [ ],
"createMethods": ["discovery"],
"paramTypes": [
{
"id": "e3e6e596-0cd4-42a3-8401-ccf6349314b7",
"name": "address",
"displayName": "Address",
"type": "QString",
"readOnly": true
},
{
"id": "34c8f771-4141-4183-9eaf-becbaf362ac8",
"name": "type",
"displayName": "Type",
"type": "QString",
"inputType": "TextLine",
"readOnly": true
}
],
"stateTypes": [
{
"id": "78fa12c0-246c-4112-8be6-5943d3c3cda5",
"name": "digitalOutput1",
"displayName": "Digital output 1",
"displayNameEvent": "Digital output 1 changed",
"displayNameAction": "Set digital output 1",
"type": "bool",
"defaultValue": false,
"writable": true
},
{
"id": "c7d2f4a8-2b13-4a48-81a8-72f4908c775b",
"name": "digitalOutput2",
"displayName": "Digital output 2",
"displayNameEvent": "Digital output 2 changed",
"displayNameAction": "Set digital output 2",
"type": "bool",
"defaultValue": false,
"writable": true
},
{
"id": "4b2ac595-eba9-4364-8cd7-00ff8bccda5a",
"name": "digitalOutput3",
"displayName": "Digital output 3",
"displayNameEvent": "Digital output 3 changed",
"displayNameAction": "Set digital output 3",
"type": "bool",
"defaultValue": false,
"writable": true
},
{
"id": "bbbd1863-ef04-4687-803d-3c9ccdfc8d8f",
"name": "digitalOutput4",
"displayName": "Digital output 4",
"displayNameEvent": "Digital output 4 changed",
"displayNameAction": "Set digital output 4",
"type": "bool",
"defaultValue": false,
"writable": true
},
{
"id": "50855d2b-a700-4030-8674-fee00cc0b4e2",
"name": "digitalOutput5",
"displayName": "Digital output 5",
"displayNameEvent": "Digital output 5 changed",
"displayNameAction": "Set digital output 5",
"type": "bool",
"defaultValue": false,
"writable": true
},
{
"id": "a91ce593-09ba-4754-8a2e-e3f507313585",
"name": "digitalOutput6",
"displayName": "Digital output 6",
"displayNameEvent": "Digital output 6 changed",
"displayNameAction": "Set digital output 6",
"type": "bool",
"defaultValue": false,
"writable": true
},
{
"id": "5f46047c-b00d-486f-b169-b738fbc89cdb",
"name": "digitalOutput7",
"displayName": "Digital output 7",
"displayNameEvent": "Digital output 7 changed",
"displayNameAction": "Set digital output 7",
"type": "bool",
"defaultValue": false,
"writable": true
},
{
"id": "63334a17-0847-4f53-8007-1b5e72b88aa8",
"name": "digitalOutput8",
"displayName": "Digital output 8",
"displayNameEvent": "Digital output 8 changed",
"displayNameAction": "Set digital output 8",
"type": "bool",
"defaultValue": false,
"writable": true
}
]
}
]
}
]
}

280
onewire/onewire.cpp Normal file
View File

@ -0,0 +1,280 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Bernhard Trinnes <bernhard.trinnes@guh.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "onewire.h"
#include "extern-plugininfo.h"
OneWire::OneWire(QObject *parent) :
QObject(parent)
{
}
OneWire::~OneWire()
{
OW_finish();
}
bool OneWire::init(const QByteArray &owfsInitArguments)
{
//QByteArray initArguments;
//Test OWFS arguments
//initArguments.append("--fake 28 --fake 10"); //fake temperature sensors
//initArguments.append("--fake 29 --fake 12 --fake 05"); //fake temperature sensor
//Test i2c
//initArguments.append("--i2c=ALL:ALL");
if (OW_init(owfsInitArguments) < 0) {
qWarning(dcOneWire()) << "ERROR initialising one wire" << strerror(errno);
return false;
}
m_path = "/";
return true;
}
bool OneWire::discoverDevices()
{
char *dirBuffer = nullptr;
size_t dirLength ;
if (OW_get(m_path, &dirBuffer, &dirLength) < 0) {
qWarning(dcOneWire()) << "DIRECTORY ERROR" << strerror(errno);
return false;
}
qDebug(dcOneWire()) << "Directory has members" << dirBuffer;
QList<QByteArray> dirMembers ;
dirMembers = QByteArray(dirBuffer, dirLength).split(',');
free(dirBuffer);
QList<OneWireDevice> oneWireDevices;
foreach(QByteArray member, dirMembers) {
/* Other system members:
* bus.0
* uncached
* settings
* system
* statistics
* structure
* simultaneous
* alarm
*/
int family = member.split('.').first().toInt(nullptr, 16);
if (family != 0) {
member.remove(member.indexOf('/'), 1);
QByteArray type;
OneWireDevice device;
device.family = family;
device.address = member;
device.id = member.split('.').last();
device.type = getValue(member, "type");
oneWireDevices.append(device);
}
}
if(!oneWireDevices.isEmpty()) {
emit devicesDiscovered(oneWireDevices);
}
return true;
}
bool OneWire::interfaceIsAvailable()
{
return true;
}
bool OneWire::isConnected(const QByteArray &address)
{
Q_UNUSED(address)
QByteArray fullPath;
fullPath.append(m_path);
fullPath.append(address);
fullPath.append('\0');
if(OW_present(fullPath) < 0)
return false;
return true;
}
/* Takes a path and filename and prints the 1-wire value */
/* makes sure the bridging "/" in the path is correct */
/* watches for total length and free allocated space */
QByteArray OneWire::getValue(const QByteArray &address, const QByteArray &type)
{
char * getBuffer ;
size_t getLength ;
QByteArray devicePath;
devicePath.append(m_path);
if(!m_path.endsWith('/'))
devicePath.append('/');
devicePath.append(address);
devicePath.append('/');
devicePath.append(type);
devicePath.append('\0');
if (OW_get(devicePath, &getBuffer, &getLength) < 0) {
qWarning(dcOneWire()) << "ERROR reading" << devicePath << strerror(errno);
}
qDebug(dcOneWire()) << "Device value" << devicePath << getBuffer;
QByteArray value = QByteArray(getBuffer, getLength);
free(getBuffer);
return value;
}
void OneWire::setValue(const QByteArray &address, const QByteArray &type, const QByteArray &value)
{
Q_UNUSED(value)
QByteArray devicePath;
devicePath.append(m_path);
if(!m_path.endsWith('/'))
devicePath.append('/');
devicePath.append(address);
devicePath.append('/');
devicePath.append(type);
devicePath.append('\0');
if (OW_put(devicePath, value, value.length()) < 0) {
qWarning(dcOneWire()) << "ERROR reading" << devicePath << strerror(errno);
}
}
double OneWire::getTemperature(const QByteArray &address)
{
QByteArray temperature = getValue(address, "temperature");
qDebug(dcOneWire()) << "Temperature" << temperature << temperature.replace(',','.').toDouble();
return temperature.toDouble();
}
QByteArray OneWire::getType(const QByteArray &address)
{
QByteArray type = getValue(address, "type");
return type;
}
bool OneWire::getSwitchOutput(const QByteArray &address, SwitchChannel channel)
{
QByteArray c;
c.append("PIO.");
switch (channel) {
case PIO_A:
c.append('A');
break;
case PIO_B:
c.append('B');
break;
case PIO_C:
c.append('C');
break;
case PIO_D:
c.append('D');
break;
case PIO_E:
c.append('E');
break;
case PIO_F:
c.append('F');
break;
case PIO_G:
c.append('G');
break;
case PIO_H:
c.append('H');
break;
}
QByteArray state = getValue(address, c);
qDebug(dcOneWire()) << "Switch state" << state.toInt();
return state.toInt();
}
bool OneWire::getSwitchInput(const QByteArray &address, SwitchChannel channel)
{
QByteArray c;
c.append("sensed.");
switch (channel) {
case PIO_A:
c.append('A');
break;
case PIO_B:
c.append('B');
break;
case PIO_C:
c.append('C');
break;
case PIO_D:
c.append('D');
break;
case PIO_E:
c.append('E');
break;
case PIO_F:
c.append('F');
break;
case PIO_G:
c.append('G');
break;
case PIO_H:
c.append('H');
break;
}
QByteArray state = getValue(address, c);
qDebug(dcOneWire()) << "Switch state" << state.toInt();
return state.toInt();
}
void OneWire::setSwitchOutput(const QByteArray &address, SwitchChannel channel, bool state)
{
QByteArray c;
c.append("PIO.");
switch (channel) {
case PIO_A:
c.append('A');
break;
case PIO_B:
c.append('B');
break;
case PIO_C:
c.append('C');
break;
case PIO_D:
c.append('D');
break;
case PIO_E:
c.append('E');
break;
case PIO_F:
c.append('F');
break;
case PIO_G:
c.append('G');
break;
case PIO_H:
c.append('H');
break;
}
setValue(address, c, QVariant(state).toByteArray());
}

85
onewire/onewire.h Normal file
View File

@ -0,0 +1,85 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Bernhard Trinnes <bernhard.trinnes@guh.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef ONEWIRE_H
#define ONEWIRE_H
#include "owcapi.h"
#include <QObject>
class OneWire : public QObject
{
Q_OBJECT
public:
enum OneWireProperty {
Address, //The entire 64-bit unique ID
Crc, //The 8-bit error correction
Family, //The 8-bit family code
Id, //The 48-bit middle portion of the unique ID number.
Locator, //Uses an extension of the 1-wire design from iButtonLink company that associated 1-wire physical connections with a unique 1-wire code.
Type //Part name assigned by Dallas Semi. E.g. DS2401
};
enum SwitchChannel {
PIO_A,
PIO_B,
PIO_C,
PIO_D,
PIO_E,
PIO_F,
PIO_G,
PIO_H
};
struct OneWireDevice {
QByteArray address;
int family;
QByteArray id;
QByteArray type;
};
explicit OneWire(QObject *parent = nullptr);
~OneWire();
bool init(const QByteArray &owfsInitArguments);
QByteArray getPath();
bool discoverDevices();
bool interfaceIsAvailable();
bool isConnected(const QByteArray &address);
double getTemperature(const QByteArray &address);
QByteArray getType(const QByteArray &address);
bool getSwitchOutput(const QByteArray &address, SwitchChannel channel);
void setSwitchOutput(const QByteArray &address, SwitchChannel channel, bool state);
bool getSwitchInput(const QByteArray &address, SwitchChannel channel);
private:
QByteArray m_path;
QByteArray getValue(const QByteArray &address, const QByteArray &deviceType);
void setValue(const QByteArray &address, const QByteArray &deviceType, const QByteArray &value);
signals:
void devicesDiscovered(QList<OneWireDevice> devices);
};
#endif // ONEWIRE_H

17
onewire/onewire.pro Normal file
View File

@ -0,0 +1,17 @@
include(../plugins.pri)
TARGET = $$qtLibraryTarget(nymea_devicepluginonewire)
LIBS += \
-low \
-lowcapi \
SOURCES += \
devicepluginonewire.cpp \
onewire.cpp \
HEADERS += \
devicepluginonewire.h \
onewire.h \