Skip to content
55 changes: 39 additions & 16 deletions doc/Applikationsbeschreibung-SmartHomeBridge.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,34 @@ In den Basiseinstellungen wird die Auswahl der angebunden Smart Home System vorg
Name der Smart Home Bridge.
Bei manchen Smart Home Systemen wird dieser beim Koppeln angezeigt.


<!-- DOCEND -->
## Unterstütze Smarthomesysteme

Folgende Smart Home Systeme werden unterstüzt:

<!-- DOC -->
#### Apple HomeKit
### Matter

Über die Matter Unterstützung können KNX Geräte über Matter fähige Geräte gesteuert werden.
Z.B. Google Home, Apple Home


<!-- DOC HelpContext="PairingCodeMatter" -->
#### Kopplungscode

Über Apple HomeKit oder Google Home können die KNX Geräte gesteuert werden.
Der Kopplungscode wird nur beim erstmaligen Koppeln der Bridge verwendet.
Das Koppeln von weiteren Apps erfolgt in der App, in der die erste Kopplung durchgeführt wurde.

Koppelung in Apple Home:

- "Gerät hinzufügen" wählen
- "Weitere Optionen..." wählen
- Nun sollte die Bridge sichtbar sein. Den Kopplungscode der in ETS eingestellt wurde (Standardwert 29710235) eingeben und die Meldung das es sich um ein nicht zertifiziertes Gerät handelt bestätigen.
- Danach den Setup-Wizard für alle Geräte durchführen.

<!-- DOC -->
### Apple HomeKit

Über Apple HomeKit können die KNX Geräte gesteuert werden. Es werden bis zu 149 Geräte unterstützt, jedoch derzeit nur maximal 60 empfohlen. Das Limit ergibt sich aus eine Beschränkung der Anzahl der Accessories bei einem HomeKit Gerät mit maximal 150. Eines davon repräsentiert das Bridge Gerät.

Expand All @@ -34,6 +56,21 @@ Nachdem die Bridge über ETS programmiert wurde, kann sie mit Apple Homekit verb

Sollte nachträglich eine Gerätetype sich ändern, z.B. eine Lampe wird zu einer Jalousie, oder eine Untertype ändert sich z.B. ein CO2 Sensor wird zu einem Kontakt, muss zuerst das Gerät deaktiviert werden. Danach die in der Home App warten bis das Gerät verschwunden ist und danach kann das Gerät wieder aktiviert werden.


<!-- DOC HelpContext="PairingCodeHomeKit" -->
#### Kopplungscode

Über Apple HomeKit können die KNX Geräte gesteuert werden. Es werden bis zu 149 Geräte unterstützt. Das Limit ergibt sich aus eine Beschränkung der Anzahl der Accessories bei einem HomeKit Gerät mit maximal 150. Eines davon repräsentiert das Bridge Gerät.

Nachdem die Bridge über ETS programmiert wurde, kann sie mit Apple Homekit verbunden:

- "Gerät hinzufügen" wählen
- "Weitere Optionen..." wählen
- Nun sollte die Bridge sichtbar sein. Den Kopplungscode der in ETS eingestellt wurde (Standardwert 46637726) eingeben und die Meldung das es sich um ein nicht zertifiziertes Gerät handelt bestätigen.
- Danach den Setup-Wizard für alle Geräte durchführen.

Sollte nachträglich eine Gerätetype sich ändern, z.B. eine Lampe wird zu einer Jalousie, oder eine Untertype ändert sich z.B. ein CO2 Sensor wird zu einem Kontakt, muss zuerst das Gerät deaktiviert werden. Danach die in der Home App warten bis das Gerät verschwunden ist und danach kann das Gerät wieder aktiviert werden.

<!-- DOC -->
### Hue Emulation (Nur für Alexa)

Expand Down Expand Up @@ -62,20 +99,6 @@ Die Philips HUE Emulation unterstützt nur Lampen. Geräte mit dieser Einstellun

Die Philips HUE Emulation unterstützt nur Lampen. Geräte mit dieser Einstellung können aber als Dimmbare Lampe in HUE emuliert werde, um trotzdem eine Steuerung über die Smart Home Bridge zu Ermöglichen.

<!-- DOC -->
### Kopplungscode

Über Apple HomeKit können die KNX Geräte gesteuert werden. Es werden bis zu 149 Geräte unterstützt. Das Limit ergibt sich aus eine Beschränkung der Anzahl der Accessories bei einem HomeKit Gerät mit maximal 150. Eines davon repräsentiert das Bridge Gerät.

Nachdem die Bridge über ETS programmiert wurde, kann sie mit Apple Homekit verbunden:

- "Gerät hinzufügen" wählen
- "Weitere Optionen..." wählen
- Nun sollte die Bridge sichtbar sein. Den Kopplungscode der in ETS eingestellt wurde (Standardwert 46637726) eingeben und die Meldung das es sich um ein nicht zertifiziertes Gerät handelt bestätigen.
- Danach den Setup-Wizard für alle Geräte durchführen.

Sollte nachträglich eine Gerätetype sich ändern, z.B. eine Lampe wird zu einer Jalousie, oder eine Untertype ändert sich z.B. ein CO2 Sensor wird zu einem Kontakt, muss zuerst das Gerät deaktiviert werden. Danach die in der Home App warten bis das Gerät verschwunden ist und danach kann das Gerät wieder aktiviert werden.

<!-- DOC HelpContext="Kanalauswahl" -->
# Gerätetypen

Expand Down
2 changes: 1 addition & 1 deletion src/Alarm/HomeKitAlarm.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#ifndef SMARTHOMEBRIDGE_DEVICESONLY
#if !defined(SMARTHOMEBRIDGE_DEVICESONLY) && defined(SMARTHOMEBRIDGE_HOMEKIT)
#include "HomeKitAlarm.h"

HomeKitAlarm::HomeKitAlarm(int device) :
Expand Down
19 changes: 17 additions & 2 deletions src/Alarm/KnxChannelAlarm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,23 @@ void KnxChannelAlarm::add(AlarmBridge* sensorBridge)
{
sensorBridges.push_back(sensorBridge);
sensorBridge->initialize(this);
auto value = mainFunctionValue();
sensorBridge->setDetected(value);
}

void KnxChannelAlarm::syncBridgeState(ChannelBridge *bridge)
{
if (bridge == nullptr)
return;

auto sensorBridge = static_cast<AlarmBridge *>(bridge);
sensorBridge->setDetected(mainFunctionValue());
}

void KnxChannelAlarm::syncAllBridgeStates()
{
for (auto it = sensorBridges.begin(); it != sensorBridges.end(); ++it)
{
syncBridgeState(*it);
}
}

void KnxChannelAlarm::remove(AlarmBridge* sensorBridge)
Expand Down
2 changes: 2 additions & 0 deletions src/Alarm/KnxChannelAlarm.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class KnxChannelAlarm : public KnxChannelBase
void remove(AlarmBridge* sensorBridge);
virtual ChannelBridge* createBridgeDevice(BridgeBase& bridge) override;
virtual void deleteBridgeDevice(ChannelBridge* device) override;
virtual void syncBridgeState(ChannelBridge* bridge) override;
virtual void syncAllBridgeStates() override;
AlarmType getAlarmType();
protected:
virtual void setup() override;
Expand Down
89 changes: 89 additions & 0 deletions src/Alarm/MatterAlarm.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#include "Alarm/MatterAlarm.h"

#include "MatterBridge.h"
#include "Matter/MatterBridgeCommon.h"

#include <esp_matter_bridge.h>

MatterAlarmBridge::MatterAlarmBridge(MatterBridge *bridge) : MatterBridgeDeviceBase(bridge)
{
}

void MatterAlarmBridge::setup(uint8_t _channelIndex)
{
if (_bridge == nullptr || _bridge->node() == nullptr)
return;

uint32_t matterType = esp_matter::endpoint::occupancy_sensor::get_device_type_id();
switch (_channel->getAlarmType())
{
case AlarmTypeContact:
matterType = esp_matter::endpoint::contact_sensor::get_device_type_id();
break;
case AlarmTypeCarbonMonoxid:
case AlarmTypeSmoke:
matterType = esp_matter::endpoint::smoke_co_alarm::get_device_type_id();
break;
case AlarmTypeCarbonDioxid:
matterType = esp_matter::endpoint::air_quality_sensor::get_device_type_id();
break;
case AlarmTypeLeak:
matterType = esp_matter::endpoint::water_leak_detector::get_device_type_id();
break;
default:
matterType = esp_matter::endpoint::occupancy_sensor::get_device_type_id();
break;
}

_device = esp_matter_bridge::create_device(_bridge->node(), _bridge->parentEndpointId(), matterType,
static_cast<MatterBridgeDeviceBase *>(this));
if (_device != nullptr)
{
matterbridge::setDeviceName(_device, _channel->getNameInUTF8());
setDetected(_channel->mainFunctionValue());
}
}

void MatterAlarmBridge::setDetected(bool detected)
{
if (_device == nullptr)
return;

auto alarmType = _channel->getAlarmType();
if (alarmType == AlarmTypeContact || alarmType == AlarmTypeLeak)
{
matterbridge::reportBool(_device->persistent_info.device_endpoint_id, matterbridge::boolStateClusterId,
matterbridge::boolStateAttrId, detected);
}
else if (alarmType == AlarmTypeSmoke)
{
matterbridge::reportU8(_device->persistent_info.device_endpoint_id, matterbridge::smokeCoAlarmClusterId,
matterbridge::smokeStateAttrId,
detected ? static_cast<uint8_t>(chip::app::Clusters::SmokeCoAlarm::AlarmStateEnum::kCritical)
: static_cast<uint8_t>(chip::app::Clusters::SmokeCoAlarm::AlarmStateEnum::kNormal));
}
else if (alarmType == AlarmTypeCarbonMonoxid)
{
matterbridge::reportU8(_device->persistent_info.device_endpoint_id, matterbridge::smokeCoAlarmClusterId,
matterbridge::coStateAttrId,
detected ? static_cast<uint8_t>(chip::app::Clusters::SmokeCoAlarm::AlarmStateEnum::kCritical)
: static_cast<uint8_t>(chip::app::Clusters::SmokeCoAlarm::AlarmStateEnum::kNormal));
}
else if (alarmType == AlarmTypeCarbonDioxid)
{
matterbridge::reportU8(_device->persistent_info.device_endpoint_id, matterbridge::airQualityClusterId,
matterbridge::measuredAirQualityAttrId,
detected ? static_cast<uint8_t>(chip::app::Clusters::AirQuality::AirQualityEnum::kPoor)
: static_cast<uint8_t>(chip::app::Clusters::AirQuality::AirQualityEnum::kGood));
}
else
{
matterbridge::reportU8(_device->persistent_info.device_endpoint_id, matterbridge::occupancyClusterId,
matterbridge::occupancyAttrId, detected ? 1 : 0);
}
}

void MatterAlarmBridge::handleMatterAttribute(esp_matter::attribute::callback_type_t, uint32_t,
uint32_t, esp_matter_attr_val_t *)
{
}
15 changes: 15 additions & 0 deletions src/Alarm/MatterAlarm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include "Matter/MatterBridgeDeviceBase.h"
#include "Alarm/KnxChannelAlarm.h"

class MatterAlarmBridge final : public MatterBridgeDeviceBase, public AlarmBridge
{
public:
explicit MatterAlarmBridge(MatterBridge *bridge);

void setup(uint8_t channelIndex) override;
void setDetected(bool detected) override;
void handleMatterAttribute(esp_matter::attribute::callback_type_t type, uint32_t clusterId,
uint32_t attributeId, esp_matter_attr_val_t *val) override;
};
1 change: 1 addition & 0 deletions src/Baggages/Help_de/BRI-Apple-HomeKit.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ Nachdem die Bridge über ETS programmiert wurde, kann sie mit Apple Homekit verb

Sollte nachträglich eine Gerätetype sich ändern, z.B. eine Lampe wird zu einer Jalousie, oder eine Untertype ändert sich z.B. ein CO2 Sensor wird zu einem Kontakt, muss zuerst das Gerät deaktiviert werden. Danach die in der Home App warten bis das Gerät verschwunden ist und danach kann das Gerät wieder aktiviert werden.


6 changes: 6 additions & 0 deletions src/Baggages/Help_de/BRI-Matter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
### Matter

Über die Matter Unterstützung können KNX Geräte über Matter fähige Geräte gesteuert werden.
Z.B. Google Home, Apple Home


1 change: 0 additions & 1 deletion src/Baggages/Help_de/BRI-Name.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@
Name der Smart Home Bridge.
Bei manchen Smart Home Systemen wird dieser beim Koppeln angezeigt.


13 changes: 13 additions & 0 deletions src/Baggages/Help_de/BRI-PairingCodeMatter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
### Kopplungscode

Über Apple HomeKit oder Google Home können die KNX Geräte gesteuert werden.
Der Kopplungscode wird nur beim erstmaligen Koppeln der Bridge verwendet.
Das Koppeln von weiteren Apps erfolgt in der App, in der die erste Kopplung durchgeführt wurde.

Koppelung in Apple Home:

- "Gerät hinzufügen" wählen
- "Weitere Optionen..." wählen
- Nun sollte die Bridge sichtbar sein. Den Kopplungscode der in ETS eingestellt wurde (Standardwert 29710235) eingeben und die Meldung das es sich um ein nicht zertifiziertes Gerät handelt bestätigen.
- Danach den Setup-Wizard für alle Geräte durchführen.

1 change: 1 addition & 0 deletions src/ChannelOwnerModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class ChannelOwnerModule : public OpenKNX::Module
OpenKNX::Channel** _pChannels = nullptr;
public:
void setNumberOfChannels(uint8_t numberOfChannels);
uint8_t numberOfChannels() const { return _numberOfChannels; }
~ChannelOwnerModule();

virtual OpenKNX::Channel* createChannel(uint8_t _channelIndex /* this parameter is used in macros, do not rename */);
Expand Down
2 changes: 1 addition & 1 deletion src/Dimmer/HomeKitDimmer.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#ifndef SMARTHOMEBRIDGE_DEVICESONLY
#if !defined(SMARTHOMEBRIDGE_DEVICESONLY) && defined(SMARTHOMEBRIDGE_HOMEKIT)

#include "HomeKitDimmer.h"

Expand Down
16 changes: 16 additions & 0 deletions src/Dimmer/KnxChannelDimmer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,25 @@ void KnxChannelDimmer::add(DimmerBridge *dimmerBridge)
{
dimmerBridges.push_back(dimmerBridge);
dimmerBridge->initialize(this);
}

void KnxChannelDimmer::syncBridgeState(ChannelBridge *bridge)
{
if (bridge == nullptr)
return;

auto dimmerBridge = static_cast<DimmerBridge *>(bridge);
dimmerBridge->setBrightness(koGet(KO_DIMMER_FEEDBACK));
}

void KnxChannelDimmer::syncAllBridgeStates()
{
for (auto it = dimmerBridges.begin(); it != dimmerBridges.end(); ++it)
{
syncBridgeState(*it);
}
}

void KnxChannelDimmer::remove(DimmerBridge *dimmerBridge)
{
dimmerBridges.remove(dimmerBridge);
Expand Down
2 changes: 2 additions & 0 deletions src/Dimmer/KnxChannelDimmer.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ class KnxChannelDimmer : public KnxChannelBase
void remove(DimmerBridge* dimmerBridge);
virtual ChannelBridge* createBridgeDevice(BridgeBase& bridge) override;
virtual void deleteBridgeDevice(ChannelBridge* device) override;
virtual void syncBridgeState(ChannelBridge* bridge) override;
virtual void syncAllBridgeStates() override;

protected:
uint8_t lastBrighness = 100;
Expand Down
68 changes: 68 additions & 0 deletions src/Dimmer/MatterDimmer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#include "Dimmer/MatterDimmer.h"

#include "MatterBridge.h"
#include "Matter/MatterBridgeCommon.h"

#include "knxprod.h"
#include <esp_matter_bridge.h>

MatterDimmerBridge::MatterDimmerBridge(MatterBridge *bridge) : MatterBridgeDeviceBase(bridge)
{
}

namespace
{
uint8_t percentToMatterLevel(uint8_t percent)
{
uint16_t clamped = static_cast<uint16_t>(std::clamp<int>(percent, 0, 100));
return static_cast<uint8_t>((clamped * 254u + 50u) / 100u);
}

uint8_t matterLevelToPercent(uint8_t level)
{
uint16_t clamped = static_cast<uint16_t>(std::clamp<int>(level, 0, 254));
return static_cast<uint8_t>((clamped * 100u + 127u) / 254u);
}
}

void MatterDimmerBridge::setup(uint8_t _channelIndex)
{
if (_bridge == nullptr || _bridge->node() == nullptr)
return;

uint32_t matterType = ParamBRI_CHDeviceType == 20
? esp_matter::endpoint::dimmable_light::get_device_type_id()
: esp_matter::endpoint::dimmable_plugin_unit::get_device_type_id();

_device = esp_matter_bridge::create_device(_bridge->node(), _bridge->parentEndpointId(), matterType,
static_cast<MatterBridgeDeviceBase *>(this));
if (_device != nullptr)
{
matterbridge::setDeviceName(_device, _channel->getNameInUTF8());
setBrightness(_channel->mainFunctionValue() ? 100 : 0);
}
}

void MatterDimmerBridge::setBrightness(uint8_t brightness)
{
if (_device == nullptr)
return;

matterbridge::reportBool(_device->persistent_info.device_endpoint_id, matterbridge::onOffClusterId,
matterbridge::onOffAttrId, brightness > 0);
matterbridge::reportU8(_device->persistent_info.device_endpoint_id, matterbridge::levelControlClusterId,
matterbridge::currentLevelAttrId, percentToMatterLevel(brightness));
}

void MatterDimmerBridge::handleMatterAttribute(esp_matter::attribute::callback_type_t, uint32_t clusterId,
uint32_t attributeId, esp_matter_attr_val_t *val)
{
if (clusterId == matterbridge::onOffClusterId && attributeId == matterbridge::onOffAttrId)
{
_channel->commandPower(this, val->val.b);
}
else if (clusterId == matterbridge::levelControlClusterId && attributeId == matterbridge::currentLevelAttrId)
{
_channel->commandBrightness(this, matterLevelToPercent(val->val.u8));
}
}
15 changes: 15 additions & 0 deletions src/Dimmer/MatterDimmer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include "Matter/MatterBridgeDeviceBase.h"
#include "Dimmer/KnxChannelDimmer.h"

class MatterDimmerBridge final : public MatterBridgeDeviceBase, public DimmerBridge
{
public:
explicit MatterDimmerBridge(MatterBridge *bridge);

void setup(uint8_t channelIndex) override;
void setBrightness(uint8_t brightness) override;
void handleMatterAttribute(esp_matter::attribute::callback_type_t type, uint32_t clusterId,
uint32_t attributeId, esp_matter_attr_val_t *val) override;
};
Loading