Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
/bundles/org.openhab.binding.deutschebahn/ @soenkekueper
/bundles/org.openhab.binding.digiplex/ @rmichalak
/bundles/org.openhab.binding.digitalstrom/ @openhab/add-ons-maintainers
/bundles/org.openhab.binding.dirigera/ @weymann
/bundles/org.openhab.binding.dlinksmarthome/ @MikeJMajor
/bundles/org.openhab.binding.dmx/ @openhab/add-ons-maintainers
/bundles/org.openhab.binding.dolbycp/ @Cybso
Expand Down
5 changes: 5 additions & 0 deletions bom/openhab-addons/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,11 @@
<artifactId>org.openhab.binding.digitalstrom</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.dirigera</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.dlinksmarthome</artifactId>
Expand Down
13 changes: 13 additions & 0 deletions bundles/org.openhab.binding.dirigera/NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
This content is produced and maintained by the openHAB project.

* Project home: https://www.openhab.org

== Declared Project Licenses

This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.

== Source Code

https://github.com/openhab/openhab-addons
734 changes: 734 additions & 0 deletions bundles/org.openhab.binding.dirigera/README.md

Large diffs are not rendered by default.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions bundles/org.openhab.binding.dirigera/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
<version>5.0.0-SNAPSHOT</version>
</parent>

<artifactId>org.openhab.binding.dirigera</artifactId>

<name>openHAB Add-ons :: Bundles :: Dirigera Binding</name>
<dependencies>
<!-- version needs to match with other projects like org.openhab.io.openhabcloud.pom.xml -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20231013</version>
<scope>compile</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.dirigera-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>

<feature name="openhab-binding-dirigera" description="Dirigera Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.dirigera/${project.version}</bundle>
</feature>
</features>

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2010-2025 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dirigera.internal;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.events.EventPublisher;
import org.openhab.core.thing.binding.BaseDynamicCommandDescriptionProvider;
import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService;
import org.openhab.core.thing.link.ItemChannelLinkRegistry;
import org.openhab.core.thing.type.DynamicCommandDescriptionProvider;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

/**
* Dynamic provider of command options while leaving other state description fields as original.
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
@Component(service = { DynamicCommandDescriptionProvider.class, DirigeraCommandProvider.class })
public class DirigeraCommandProvider extends BaseDynamicCommandDescriptionProvider {
@Activate
public DirigeraCommandProvider(final @Reference EventPublisher eventPublisher, //
final @Reference ItemChannelLinkRegistry itemChannelLinkRegistry, //
final @Reference ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService) {
this.eventPublisher = eventPublisher;
this.itemChannelLinkRegistry = itemChannelLinkRegistry;
this.channelTypeI18nLocalizationService = channelTypeI18nLocalizationService;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*
* Copyright (c) 2010-2025 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dirigera.internal;

import static org.openhab.binding.dirigera.internal.Constants.*;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.WWWAuthenticationProtocolHandler;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.openhab.binding.dirigera.internal.discovery.DirigeraDiscoveryService;
import org.openhab.binding.dirigera.internal.handler.DirigeraHandler;
import org.openhab.binding.dirigera.internal.handler.airpurifier.AirPurifierHandler;
import org.openhab.binding.dirigera.internal.handler.blind.BlindHandler;
import org.openhab.binding.dirigera.internal.handler.controller.BlindsControllerHandler;
import org.openhab.binding.dirigera.internal.handler.controller.DoubleShortcutControllerHandler;
import org.openhab.binding.dirigera.internal.handler.controller.LightControllerHandler;
import org.openhab.binding.dirigera.internal.handler.controller.ShortcutControllerHandler;
import org.openhab.binding.dirigera.internal.handler.controller.SoundControllerHandler;
import org.openhab.binding.dirigera.internal.handler.light.ColorLightHandler;
import org.openhab.binding.dirigera.internal.handler.light.DimmableLightHandler;
import org.openhab.binding.dirigera.internal.handler.light.SwitchLightHandler;
import org.openhab.binding.dirigera.internal.handler.light.TemperatureLightHandler;
import org.openhab.binding.dirigera.internal.handler.plug.PowerPlugHandler;
import org.openhab.binding.dirigera.internal.handler.plug.SimplePlugHandler;
import org.openhab.binding.dirigera.internal.handler.plug.SmartPlugHandler;
import org.openhab.binding.dirigera.internal.handler.repeater.RepeaterHandler;
import org.openhab.binding.dirigera.internal.handler.scene.SceneHandler;
import org.openhab.binding.dirigera.internal.handler.sensor.AirQualityHandler;
import org.openhab.binding.dirigera.internal.handler.sensor.ContactSensorHandler;
import org.openhab.binding.dirigera.internal.handler.sensor.MotionLightSensorHandler;
import org.openhab.binding.dirigera.internal.handler.sensor.MotionSensorHandler;
import org.openhab.binding.dirigera.internal.handler.sensor.WaterSensorHandler;
import org.openhab.binding.dirigera.internal.handler.speaker.SpeakerHandler;
import org.openhab.core.i18n.LocationProvider;
import org.openhab.core.storage.Storage;
import org.openhab.core.storage.StorageService;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* The {@link DirigeraHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
@Component(configurationPid = "binding.dirigera", service = ThingHandlerFactory.class)
public class DirigeraHandlerFactory extends BaseThingHandlerFactory {
private final Logger logger = LoggerFactory.getLogger(DirigeraHandlerFactory.class);
private final DirigeraStateDescriptionProvider stateProvider;
private final DirigeraDiscoveryService discoveryService;
private final DirigeraCommandProvider commandProvider;
private final LocationProvider locationProvider;
private final Storage<String> bindingStorage;
private final HttpClient insecureClient;

@Activate
public DirigeraHandlerFactory(@Reference StorageService storageService,
final @Reference DirigeraDiscoveryService discovery, final @Reference LocationProvider locationProvider,
final @Reference DirigeraCommandProvider commandProvider,
final @Reference DirigeraStateDescriptionProvider stateProvider) {
this.locationProvider = locationProvider;
this.commandProvider = commandProvider;
this.discoveryService = discovery;
this.stateProvider = stateProvider;

this.insecureClient = new HttpClient(new SslContextFactory.Client(true));
insecureClient.setUserAgentField(null);
try {
this.insecureClient.start();
// from https://github.com/jetty-project/jetty-reactive-httpclient/issues/33#issuecomment-777771465
insecureClient.getProtocolHandlers().remove(WWWAuthenticationProtocolHandler.NAME);
} catch (Exception e) {
// catching exception is necessary due to the signature of HttpClient.start()
logger.warn("DIRIGERA FACTORY Failed to start http client: {}", e.getMessage());
throw new IllegalStateException("Could not create HttpClient", e);
}
bindingStorage = storageService.getStorage(BINDING_ID);
}

@Deactivate
public void deactivate() {
try {
insecureClient.stop();
} catch (Exception e) {
logger.warn("Failed to stop http client: {}", e.getMessage());
}
}

@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}

@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (THING_TYPE_GATEWAY.equals(thingTypeUID)) {
return new DirigeraHandler((Bridge) thing, insecureClient, bindingStorage, discoveryService,
locationProvider, commandProvider, bundleContext);
} else if (THING_TYPE_COLOR_LIGHT.equals(thingTypeUID)) {
return new ColorLightHandler(thing, COLOR_LIGHT_MAP, stateProvider);
} else if (THING_TYPE_TEMPERATURE_LIGHT.equals(thingTypeUID)) {
return new TemperatureLightHandler(thing, TEMPERATURE_LIGHT_MAP, stateProvider);
} else if (THING_TYPE_DIMMABLE_LIGHT.equals(thingTypeUID)) {
return new DimmableLightHandler(thing, TEMPERATURE_LIGHT_MAP);
} else if (THING_TYPE_SWITCH_LIGHT.equals(thingTypeUID)) {
return new SwitchLightHandler(thing, TEMPERATURE_LIGHT_MAP);
} else if (THING_TYPE_MOTION_SENSOR.equals(thingTypeUID)) {
return new MotionSensorHandler(thing, MOTION_SENSOR_MAP);
// } else if (THING_TYPE_LIGHT_SENSOR.equals(thingTypeUID)) {
// return new LightSensorHandler(thing, LIGHT_SENSOR_MAP);
} else if (THING_TYPE_MOTION_LIGHT_SENSOR.equals(thingTypeUID)) {
return new MotionLightSensorHandler(thing, MOTION_LIGHT_SENSOR_MAP);
} else if (THING_TYPE_CONTACT_SENSOR.equals(thingTypeUID)) {
return new ContactSensorHandler(thing, CONTACT_SENSOR_MAP);
} else if (THING_TYPE_SIMPLE_PLUG.equals(thingTypeUID)) {
return new SimplePlugHandler(thing, SMART_PLUG_MAP);
} else if (THING_TYPE_POWER_PLUG.equals(thingTypeUID)) {
return new PowerPlugHandler(thing, SMART_PLUG_MAP);
} else if (THING_TYPE_SMART_PLUG.equals(thingTypeUID)) {
return new SmartPlugHandler(thing, SMART_PLUG_MAP);
} else if (THING_TYPE_SPEAKER.equals(thingTypeUID)) {
return new SpeakerHandler(thing, SPEAKER_MAP);
} else if (THING_TYPE_SCENE.equals(thingTypeUID)) {
return new SceneHandler(thing, SCENE_MAP);
} else if (THING_TYPE_REPEATER.equals(thingTypeUID)) {
return new RepeaterHandler(thing, REPEATER_MAP);
} else if (THING_TYPE_LIGHT_CONTROLLER.equals(thingTypeUID)) {
return new LightControllerHandler(thing, LIGHT_CONTROLLER_MAP);
} else if (THING_TYPE_BLIND_CONTROLLER.equals(thingTypeUID)) {
return new BlindsControllerHandler(thing, BLIND_CONTROLLER_MAP);
} else if (THING_TYPE_SOUND_CONTROLLER.equals(thingTypeUID)) {
return new SoundControllerHandler(thing, SOUND_CONTROLLER_MAP);
} else if (THING_TYPE_SINGLE_SHORTCUT_CONTROLLER.equals(thingTypeUID)) {
return new ShortcutControllerHandler(thing, SHORTCUT_CONTROLLER_MAP, bindingStorage);
} else if (THING_TYPE_DOUBLE_SHORTCUT_CONTROLLER.equals(thingTypeUID)) {
return new DoubleShortcutControllerHandler(thing, SHORTCUT_CONTROLLER_MAP, bindingStorage);
} else if (THING_TYPE_AIR_QUALITY.equals(thingTypeUID)) {
return new AirQualityHandler(thing, AIR_QUALITY_MAP);
} else if (THING_TYPE_WATER_SENSOR.equals(thingTypeUID)) {
return new WaterSensorHandler(thing, WATER_SENSOR_MAP);
} else if (THING_TYPE_BLIND.equals(thingTypeUID)) {
return new BlindHandler(thing, BLINDS_MAP);
} else if (THING_TYPE_AIR_PURIFIER.equals(thingTypeUID)) {
return new AirPurifierHandler(thing, AIR_PURIFIER_MAP);
} else {
logger.debug("DIRIGERA FACTORY Request for {} doesn't match {}", thingTypeUID, THING_TYPE_GATEWAY);
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright (c) 2010-2025 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dirigera.internal;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.events.EventPublisher;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.binding.BaseDynamicStateDescriptionProvider;
import org.openhab.core.thing.events.ThingEventFactory;
import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService;
import org.openhab.core.thing.link.ItemChannelLinkRegistry;
import org.openhab.core.thing.type.DynamicStateDescriptionProvider;
import org.openhab.core.types.StateDescription;
import org.openhab.core.types.StateDescriptionFragment;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

/**
* The {@link Clip2StateDescriptionProvider} provides dynamic state descriptions of alert, effect, scene, and colour
* temperature channels whose capabilities are dynamically determined at runtime.
*
* @author Andrew Fiddian-Green - Initial contribution
*
*/
@NonNullByDefault
@Component(service = { DynamicStateDescriptionProvider.class, DirigeraStateDescriptionProvider.class })
public class DirigeraStateDescriptionProvider extends BaseDynamicStateDescriptionProvider {
private Map<ChannelUID, StateDescriptionFragment> stateDescriptionMap = new HashMap<>();

@Activate
public DirigeraStateDescriptionProvider(final @Reference EventPublisher eventPublisher,
final @Reference ItemChannelLinkRegistry itemChannelLinkRegistry,
final @Reference ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService) {
this.eventPublisher = eventPublisher;
this.itemChannelLinkRegistry = itemChannelLinkRegistry;
this.channelTypeI18nLocalizationService = channelTypeI18nLocalizationService;
}

@Override
public @Nullable StateDescription getStateDescription(Channel channel,
@Nullable StateDescription originalStateDescription, @Nullable Locale locale) {
StateDescription original = null;
StateDescriptionFragment fragment = stateDescriptionMap.get(channel.getUID());
if (fragment != null) {
original = fragment.toStateDescription();
StateDescription modified = super.getStateDescription(channel, original, locale);
if (modified == null) {
modified = original;
}
return modified;
}
return super.getStateDescription(channel, original, locale);
}

public void setStateDescription(ChannelUID channelUid, StateDescriptionFragment stateDescriptionFragment) {
StateDescription stateDescription = stateDescriptionFragment.toStateDescription();
if (stateDescription != null) {
StateDescriptionFragment old = stateDescriptionMap.get(channelUid);
stateDescriptionMap.put(channelUid, stateDescriptionFragment);
Set<String> linkedItems = null;
ItemChannelLinkRegistry compareRegistry = itemChannelLinkRegistry;
if (compareRegistry != null) {
linkedItems = compareRegistry.getLinkedItemNames(channelUid);
}
postEvent(ThingEventFactory.createChannelDescriptionChangedEvent(channelUid,
linkedItems != null ? linkedItems : Set.of(), stateDescriptionFragment, old));
}
}
}
Loading