Skip to content
Open
Show file tree
Hide file tree
Changes from 11 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 @@ -412,6 +412,7 @@
/bundles/org.openhab.binding.tuya/ @J-N-K
/bundles/org.openhab.binding.unifi/ @mgbowman @Hilbrand
/bundles/org.openhab.binding.unifiedremote/ @GiviMAD
/bundles/org.openhab.binding.unifiprotect/ @digitaldan
/bundles/org.openhab.binding.upb/ @marcusb
/bundles/org.openhab.binding.upnpcontrol/ @mherwege
/bundles/org.openhab.binding.urtsi/ @openhab/add-ons-maintainers
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 @@ -2036,6 +2036,11 @@
<artifactId>org.openhab.binding.unifiedremote</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.unifiprotect</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.upb</artifactId>
Expand Down
13 changes: 13 additions & 0 deletions bundles/org.openhab.binding.unifiprotect/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
488 changes: 488 additions & 0 deletions bundles/org.openhab.binding.unifiprotect/README.md

Large diffs are not rendered by default.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be my eyes, but i can;t see anything on this screenshot, while i think it is helpfull. While doing so i think the filesize can be reduced.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be my eyes, but i can;t see anything on this screenshot,

Sorry i don't understand, is the image not rendering for you? I just checked on my repo, and its rendering and shows where to generate a key

image

While doing so i think the filesize can be reduced.

Is there a resize tool (like imagemagick, gimp, photoshop, etc...) and options you typically use? would be happy to run my screenshots through that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant to say that the quality is low and i hardly can read it. dark blue, grey and dark green colors on a black background.
Most of the times i use irfanview, but many tools can do this. low bit PNG with decent resolution.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this file

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think the image can have a better quality with a lower size. If you need help, please paste me the original high res screenshots.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions bundles/org.openhab.binding.unifiprotect/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?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.1.0-SNAPSHOT</version>
</parent>

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

<name>openHAB Add-ons :: Bundles :: UnifiProtect Binding</name>

</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.unifiprotect-${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-unifiprotect" description="Unifi Protect Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.unifiprotect/${project.version}</bundle>
</feature>
</features>
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*
* 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.unifiprotect.internal;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;

/**
* The {@link UnifiProtectBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Dan Cunningham - Initial contribution
*/
@NonNullByDefault
public class UnifiProtectBindingConstants {

public static final String BINDING_ID = "unifiprotect";
public static final String SERVICE_ID = "org.openhab." + BINDING_ID;

// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_NVR = new ThingTypeUID(BINDING_ID, "nvr");
public static final ThingTypeUID THING_TYPE_CAMERA = new ThingTypeUID(BINDING_ID, "camera");
public static final ThingTypeUID THING_TYPE_LIGHT = new ThingTypeUID(BINDING_ID, "light");
public static final ThingTypeUID THING_TYPE_SENSOR = new ThingTypeUID(BINDING_ID, "sensor");

// List of all Configuration ids
public static final String DEVICE_ID = "deviceId";
public static final String SNAPSHOT_SEQUENCE = "sequence";

// List of all Property ids
public static final String PROPERTY_WEBRTC_URL = "webrtc-url"; // also used as base url for all webrtc urls
public static final String PROPERTY_SNAPSHOT_URL = "snapshot-url";

// List of all Channel ids

// Shared
public static final String CHANNEL_STATUS = "status";

// Camera
public static final String CHANNEL_SNAPSHOT = "snapshot";
public static final String CHANNEL_SNAPSHOT_LABEL = "Snapshot";
public static final String CHANNEL_SNAPSHOT_URL = "snapshot-url";
public static final String CHANNEL_SNAPSHOT_URL_LABEL = "Snapshot URL";
public static final String CHANNEL_MIC_VOLUME = "mic-volume";
public static final String CHANNEL_VIDEO_MODE = "video-mode";
public static final String CHANNEL_HDR_TYPE = "hdr-type";
public static final String CHANNEL_OSD_NAME = "osd-name";
public static final String CHANNEL_OSD_DATE = "osd-date";
public static final String CHANNEL_OSD_LOGO = "osd-logo";
public static final String CHANNEL_LED_ENABLED = "led-enabled";
public static final String CHANNEL_ACTIVE_PATROL_SLOT = "active-patrol-slot";
public static final String CHANNEL_RTSP_URL_HIGH = "rtsp-url-high";
public static final String CHANNEL_RTSP_URL_HIGH_LABEL = "RTSP URL High";
public static final String CHANNEL_RTSP_URL_MEDIUM = "rtsp-url-medium";
public static final String CHANNEL_RTSP_URL_MEDIUM_LABEL = "RTSP URL Medium";
public static final String CHANNEL_RTSP_URL_LOW = "rtsp-url-low";
public static final String CHANNEL_RTSP_URL_LOW_LABEL = "RTSP URL Low";
public static final String CHANNEL_RTSP_URL_PACKAGE = "rtsp-url-package";
public static final String CHANNEL_RTSP_URL_PACKAGE_LABEL = "RTSP URL Package";
public static final String CHANNEL_RTSP_URL = "rtsp-url";
public static final String CHANNEL_WEBRTC_URL = "webrtc-url";
public static final String CHANNEL_WEBRTC_URL_HIGH = "webrtc-url-high";
public static final String CHANNEL_WEBRTC_URL_HIGH_LABEL = "WebRTC URL High Quality";
public static final String CHANNEL_WEBRTC_URL_MEDIUM = "webrtc-url-medium";
public static final String CHANNEL_WEBRTC_URL_MEDIUM_LABEL = "WebRTC URL Medium Quality";
public static final String CHANNEL_WEBRTC_URL_LOW = "webrtc-url-low";
public static final String CHANNEL_WEBRTC_URL_LOW_LABEL = "WebRTC URL Low Quality";
public static final String CHANNEL_WEBRTC_URL_PACKAGE = "webrtc-url-package";
public static final String CHANNEL_WEBRTC_URL_PACKAGE_LABEL = "WebRTC URL Package Quality";
// Triggers and Contacts
public static final String CHANNEL_MOTION = "motion";
public static final String CHANNEL_MOTION_START = "motion-start";
public static final String CHANNEL_MOTION_START_LABEL = "Motion Start";
public static final String CHANNEL_MOTION_UPDATE = "motion-update";
public static final String CHANNEL_MOTION_UPDATE_LABEL = "Motion Update";
public static final String CHANNEL_MOTION_CONTACT = "motion-contact";
public static final String CHANNEL_MOTION_SNAPSHOT = "motion-snapshot";
public static final String CHANNEL_MOTION_SNAPSHOT_LABEL = "Motion Snapshot";

public static final String CHANNEL_SMART_DETECT_AUDIO = "smart-detect-audio";
public static final String CHANNEL_SMART_DETECT_AUDIO_START = "smart-detect-audio-start";
public static final String CHANNEL_SMART_DETECT_AUDIO_START_LABEL = "Smart Detect Audio Start";
public static final String CHANNEL_SMART_DETECT_AUDIO_UPDATE = "smart-detect-audio-update";
public static final String CHANNEL_SMART_DETECT_AUDIO_UPDATE_LABEL = "Smart Detect Audio Update";
public static final String CHANNEL_SMART_DETECT_AUDIO_CONTACT = "smart-detect-audio-contact";
public static final String CHANNEL_SMART_DETECT_AUDIO_SNAPSHOT = "smart-detect-audio-snapshot";
public static final String CHANNEL_SMART_DETECT_AUDIO_SNAPSHOT_LABEL = "Smart Detect Audio Snapshot";

public static final String CHANNEL_SMART_DETECT_ZONE = "smart-detect-zone";
public static final String CHANNEL_SMART_DETECT_ZONE_START = "smart-detect-zone-start";
public static final String CHANNEL_SMART_DETECT_ZONE_START_LABEL = "Smart Detect Zone Start";
public static final String CHANNEL_SMART_DETECT_ZONE_UPDATE = "smart-detect-zone-update";
public static final String CHANNEL_SMART_DETECT_ZONE_UPDATE_LABEL = "Smart Detect Zone Update";
public static final String CHANNEL_SMART_DETECT_ZONE_CONTACT = "smart-detect-zone-contact";
public static final String CHANNEL_SMART_DETECT_ZONE_SNAPSHOT = "smart-detect-zone-snapshot";
public static final String CHANNEL_SMART_DETECT_ZONE_SNAPSHOT_LABEL = "Smart Detect Zone Snapshot";

public static final String CHANNEL_SMART_DETECT_LINE = "smart-detect-line";
public static final String CHANNEL_SMART_DETECT_LINE_START = "smart-detect-line-start";
public static final String CHANNEL_SMART_DETECT_LINE_START_LABEL = "Smart Detect Line Start";
public static final String CHANNEL_SMART_DETECT_LINE_UPDATE = "smart-detect-line-update";
public static final String CHANNEL_SMART_DETECT_LINE_UPDATE_LABEL = "Smart Detect Line Update";
public static final String CHANNEL_SMART_DETECT_LINE_CONTACT = "smart-detect-line-contact";
public static final String CHANNEL_SMART_DETECT_LINE_SNAPSHOT = "smart-detect-line-snapshot";
public static final String CHANNEL_SMART_DETECT_LINE_SNAPSHOT_LABEL = "Smart Detect Line Snapshot";

public static final String CHANNEL_SMART_DETECT_LOITER = "smart-detect-loiter";
public static final String CHANNEL_SMART_DETECT_LOITER_START = "smart-detect-loiter-start";
public static final String CHANNEL_SMART_DETECT_LOITER_START_LABEL = "Smart Detect Loiter Start";
public static final String CHANNEL_SMART_DETECT_LOITER_UPDATE = "smart-detect-loiter-update";
public static final String CHANNEL_SMART_DETECT_LOITER_UPDATE_LABEL = "Smart Detect Loiter Update";
public static final String CHANNEL_SMART_DETECT_LOITER_CONTACT = "smart-detect-loiter-contact";
public static final String CHANNEL_SMART_DETECT_LOITER_SNAPSHOT = "smart-detect-loiter-snapshot";
public static final String CHANNEL_SMART_DETECT_LOITER_SNAPSHOT_LABEL = "Smart Detect Loiter Snapshot";

public static final String CHANNEL_RING = "ring";
public static final String CHANNEL_RING_LABEL = "Ring";
public static final String CHANNEL_RING_CONTACT = "ring-contact";
public static final String CHANNEL_RING_SNAPSHOT = "ring-snapshot";
public static final String CHANNEL_RING_SNAPSHOT_LABEL = "Ring Snapshot";

// Light (floodlight)
public static final String CHANNEL_LIGHT = "light";
public static final String CHANNEL_IS_DARK = "is-dark";
public static final String CHANNEL_PIR_MOTION = "pir-motion";
public static final String CHANNEL_LAST_MOTION = "last-motion";
public static final String CHANNEL_LIGHT_MODE = "light-mode";
public static final String CHANNEL_ENABLE_AT = "enable-at";
public static final String CHANNEL_INDICATOR_ENABLED = "indicator-enabled";
public static final String CHANNEL_PIR_DURATION = "pir-duration";
public static final String CHANNEL_PIR_SENSITIVITY = "pir-sensitivity";
public static final String CHANNEL_LED_LEVEL = "led-level";

// Sensor
public static final String CHANNEL_BATTERY = "battery";
public static final String CHANNEL_CONTACT = "contact";
public static final String CHANNEL_TEMPERATURE = "temperature";
public static final String CHANNEL_HUMIDITY = "humidity";
public static final String CHANNEL_ILLUMINANCE = "illuminance";
public static final String CHANNEL_SENSOR_MOTION = "motion";
public static final String CHANNEL_ALARM_CONTACT = "alarm-contact";
public static final String CHANNEL_ALARM = "alarm";
public static final String CHANNEL_WATER_LEAK_CONTACT = "water-leak-contact";
public static final String CHANNEL_WATER_LEAK = "water-leak";
public static final String CHANNEL_TAMPER_CONTACT = "tamper-contact";
public static final String CHANNEL_TAMPER = "tamper";
public static final String CHANNEL_OPENED = "opened";
public static final String CHANNEL_CLOSED = "closed";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
* 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.unifiprotect.internal;

import java.io.IOException;
import java.util.Map;
import java.util.Set;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.unifiprotect.internal.api.UniFiProtectApiClient;
import org.openhab.binding.unifiprotect.internal.api.dto.Camera;
import org.openhab.binding.unifiprotect.internal.api.dto.Light;
import org.openhab.binding.unifiprotect.internal.api.dto.Sensor;
import org.openhab.binding.unifiprotect.internal.handler.UnifiProtectNVRHandler;
import org.openhab.core.config.discovery.AbstractThingHandlerDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.ThingHandler;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ServiceScope;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Discovery service for UniFi Access Door things.
*
* @author Dan Cunningham - Initial contribution
*/
@Component(scope = ServiceScope.PROTOTYPE, service = UnifiProtectDiscoveryService.class)
@NonNullByDefault
public class UnifiProtectDiscoveryService extends AbstractThingHandlerDiscoveryService<UnifiProtectNVRHandler> {

private final Logger logger = LoggerFactory.getLogger(UnifiProtectDiscoveryService.class);

public UnifiProtectDiscoveryService() {
super(UnifiProtectNVRHandler.class, Set.of(UnifiProtectBindingConstants.THING_TYPE_CAMERA,
UnifiProtectBindingConstants.THING_TYPE_LIGHT, UnifiProtectBindingConstants.THING_TYPE_SENSOR), 30,
false);
}

@Override
public void setThingHandler(ThingHandler handler) {
logger.debug("setThingHandler {}", handler);
if (handler instanceof UnifiProtectNVRHandler childDiscoveryHandler) {
childDiscoveryHandler.setDiscoveryService(this);
this.thingHandler = childDiscoveryHandler;
}
}

@Override
protected void startScan() {
removeOlderResults(getTimestampOfLastScan());
final UniFiProtectApiClient client = thingHandler.getApiClient();
if (client == null) {
return;
}
discoverCameras(client);
discoverLights(client);
discoverSensors(client);
}

public void discoverCameras(UniFiProtectApiClient client) {
try {
for (Camera c : client.listCameras()) {
discoverCamera(c);
}
} catch (IOException e) {
logger.trace("Camera discovery failed", e);
}
}

public void discoverLights(UniFiProtectApiClient client) {
try {
for (Light l : client.listLights()) {
discoverLight(l);
}
} catch (IOException e) {
logger.trace("Light discovery failed", e);
}
}

public void discoverSensors(UniFiProtectApiClient client) {
try {
for (Sensor s : client.listSensors()) {
discoverSensor(s);
}
} catch (IOException e) {
logger.trace("Light discovery failed", e);
}
}

public void discoverCamera(Camera c) {
ThingUID uid = new ThingUID(UnifiProtectBindingConstants.THING_TYPE_CAMERA, thingHandler.getThing().getUID(),
c.id);
Map<String, Object> props = Map.of(UnifiProtectBindingConstants.DEVICE_ID, c.id);
DiscoveryResult result = DiscoveryResultBuilder.create(uid).withBridge(thingHandler.getThing().getUID())
.withThingType(UnifiProtectBindingConstants.THING_TYPE_CAMERA).withProperties(props)
.withRepresentationProperty(UnifiProtectBindingConstants.DEVICE_ID)
.withLabel("UniFi Protect Camera: " + c.name).build();
thingDiscovered(result);
}

public void discoverLight(Light l) {
ThingUID uid = new ThingUID(UnifiProtectBindingConstants.THING_TYPE_LIGHT, thingHandler.getThing().getUID(),
l.id);
Map<String, Object> props = Map.of(UnifiProtectBindingConstants.DEVICE_ID, l.id);
DiscoveryResult result = DiscoveryResultBuilder.create(uid).withBridge(thingHandler.getThing().getUID())
.withThingType(UnifiProtectBindingConstants.THING_TYPE_LIGHT).withProperties(props)
.withRepresentationProperty(UnifiProtectBindingConstants.DEVICE_ID)
.withLabel("UniFi Protect Light: " + l.name).build();
thingDiscovered(result);
}

public void discoverSensor(Sensor s) {
ThingUID uid = new ThingUID(UnifiProtectBindingConstants.THING_TYPE_SENSOR, thingHandler.getThing().getUID(),
s.id);
Map<String, Object> props = Map.of(UnifiProtectBindingConstants.DEVICE_ID, s.id);
DiscoveryResult result = DiscoveryResultBuilder.create(uid).withBridge(thingHandler.getThing().getUID())
.withThingType(UnifiProtectBindingConstants.THING_TYPE_SENSOR).withProperties(props)
.withRepresentationProperty(UnifiProtectBindingConstants.DEVICE_ID)
.withLabel("UniFi Protect Sensor: " + s.name).build();
thingDiscovered(result);
}
}
Loading