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
14 changes: 7 additions & 7 deletions src/main/java/com/beowulfe/hap/HomekitRoot.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
package com.beowulfe.hap;

import java.io.IOException;
import java.net.InetAddress;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.beowulfe.hap.impl.HomekitRegistry;
import com.beowulfe.hap.impl.HomekitWebHandler;
import com.beowulfe.hap.impl.accessories.Bridge;
import com.beowulfe.hap.impl.connections.HomekitClientConnectionFactoryImpl;
import com.beowulfe.hap.impl.connections.SubscriptionManager;
import com.beowulfe.hap.impl.jmdns.JmdnsHomekitAdvertiser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.InetAddress;

/**
* Provides advertising and handling for Homekit accessories. This class handles the advertising of Homekit accessories and
Expand Down Expand Up @@ -69,7 +68,7 @@ public void addAccessory(HomekitAccessory accessory) {
*/
void addAccessorySkipRangeCheck(HomekitAccessory accessory) {
this.registry.add(accessory);
logger.info("Added accessory "+accessory.getLabel());
logger.info("Added accessory " + accessory.getLabel());
if (started) {
registry.reset();
webHandler.resetConnections();
Expand All @@ -84,6 +83,7 @@ void addAccessorySkipRangeCheck(HomekitAccessory accessory) {
*/
public void removeAccessory(HomekitAccessory accessory) {
this.registry.remove(accessory);
logger.info("Removed accessory " + accessory.getLabel());
if (started) {
registry.reset();
webHandler.resetConnections();
Expand Down
42 changes: 42 additions & 0 deletions src/main/java/com/beowulfe/hap/accessories/LightSensor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.beowulfe.hap.accessories;

import com.beowulfe.hap.HomekitAccessory;
import com.beowulfe.hap.HomekitCharacteristicChangeCallback;
import com.beowulfe.hap.Service;
import com.beowulfe.hap.impl.services.LightSensorService;

import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.CompletableFuture;

/**
* A light sensor that reports current ambient light level.
*
* @author Gaston Dombiak
*/
public interface LightSensor extends HomekitAccessory {

/**
* Retrieves the current ambient light level.
*
* @return a future that will contain the luminance level expressed in LUX.
*/
CompletableFuture<Double> getCurrentAmbientLightLevel();

@Override
default Collection<Service> getServices() {
return Collections.singleton(new LightSensorService(this));
}

/**
* Subscribes to changes in the current ambient light level.
*
* @param callback the function to call when the state changes.
*/
void subscribeCurrentAmbientLightLevel(HomekitCharacteristicChangeCallback callback);

/**
* Unsubscribes from changes in the current ambient light level.
*/
void unsubscribeCurrentAmbientLightLevel();
}
22 changes: 10 additions & 12 deletions src/main/java/com/beowulfe/hap/impl/HomekitRegistry.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
package com.beowulfe.hap.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.beowulfe.hap.HomekitAccessory;
import com.beowulfe.hap.Service;
import com.beowulfe.hap.characteristics.Characteristic;
import com.beowulfe.hap.impl.services.AccessoryInformationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class HomekitRegistry {

Expand Down Expand Up @@ -72,7 +66,11 @@ public List<Service> getServices(Integer aid) {
}

public Map<Integer, Characteristic> getCharacteristics(Integer aid) {
return Collections.unmodifiableMap(characteristics.get(accessories.get(aid)));
Map<Integer, Characteristic> characteristics = this.characteristics.get(accessories.get(aid));
if (characteristics == null) {
return Collections.emptyMap();
}
return Collections.unmodifiableMap(characteristics);
}

public void add(HomekitAccessory accessory) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package com.beowulfe.hap.impl.characteristics.common;

import com.beowulfe.hap.HomekitAccessory;
import com.beowulfe.hap.characteristics.StaticStringCharacteristic;

public class Name extends StaticStringCharacteristic {

public Name(HomekitAccessory accessory) {
public Name(String label) {
super("00000023-0000-1000-8000-0026BB765291",
"Name of the accessory",
accessory.getLabel());
label);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.beowulfe.hap.impl.characteristics.light;

import com.beowulfe.hap.HomekitCharacteristicChangeCallback;
import com.beowulfe.hap.accessories.LightSensor;
import com.beowulfe.hap.characteristics.EventableCharacteristic;
import com.beowulfe.hap.characteristics.FloatCharacteristic;

import java.util.concurrent.CompletableFuture;

public class AmbientLightLevelCharacteristic extends FloatCharacteristic implements EventableCharacteristic {

private final LightSensor lightSensor;

public AmbientLightLevelCharacteristic(LightSensor lightSensor) {
super("0000006B-0000-1000-8000-0026BB765291", false, true, "Current ambient light level", 0.0001, 100000,
0.0001, "lux");
this.lightSensor = lightSensor;
}

@Override
protected void setValue(Double value) throws Exception {
//Read Only
}

@Override
public void subscribe(HomekitCharacteristicChangeCallback callback) {
lightSensor.subscribeCurrentAmbientLightLevel(callback);
}

@Override
public void unsubscribe() {
lightSensor.unsubscribeCurrentAmbientLightLevel();
}

@Override
protected CompletableFuture<Double> getDoubleValue() {
return lightSensor.getCurrentAmbientLightLevel();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,7 @@ public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
boolean errorLevel = true;
if (cause instanceof IOException) {
// Decide level of logging based on exception
errorLevel = !"Connection timed out".equals(cause.getMessage());
}
boolean errorLevel = !(cause instanceof IOException);
if (errorLevel) {
LOGGER.error("Exception caught in web handler", cause);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,7 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf in,
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
boolean errorLevel = true;
if (cause instanceof IOException) {
// Decide level of logging based on exception
errorLevel = !"Connection timed out".equals(cause.getMessage());
}
boolean errorLevel = !(cause instanceof IOException);
if (errorLevel) {
logger.error("Exception in binary handler", cause);
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,5 @@
package com.beowulfe.hap.impl.json;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.json.JsonValue;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.beowulfe.hap.characteristics.Characteristic;
import com.beowulfe.hap.characteristics.EventableCharacteristic;
import com.beowulfe.hap.impl.HomekitRegistry;
Expand All @@ -21,6 +8,13 @@
import com.beowulfe.hap.impl.http.HttpRequest;
import com.beowulfe.hap.impl.http.HttpResponse;
import com.beowulfe.hap.impl.responses.NotFoundResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.json.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Map;

public class CharacteristicsController {

Expand Down Expand Up @@ -49,9 +43,19 @@ public HttpResponse get(HttpRequest request) throws Exception {
int aid = Integer.parseInt(parts[0]);
int iid = Integer.parseInt(parts[1]);
JsonObjectBuilder characteristic = Json.createObjectBuilder();
registry.getCharacteristics(aid).get(iid).supplyValue(characteristic);
Map<Integer, Characteristic> characteristicMap = registry.getCharacteristics(aid);
if (!characteristicMap.isEmpty()) {
Characteristic targetCharacteristic = characteristicMap.get(iid);
if (targetCharacteristic != null) {
targetCharacteristic.supplyValue(characteristic);

characteristics.add(characteristic.add("aid", aid).add("iid", iid).build());
characteristics.add(characteristic.add("aid", aid).add("iid", iid).build());
} else {
logger.warn("Accessory " + aid + " does not have characteristic " + iid + "Request: " + uri);
}
} else {
logger.warn("Accessory " + aid + " has no characteristics or does not exist. Request: " + uri);
}
}
try(ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
Json.createWriter(baos).write(Json.createObjectBuilder().add("characteristics", characteristics.build()).build());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@ abstract class AbstractServiceImpl implements Service {
private final List<Characteristic> characteristics = new LinkedList<>();

/**
* This constructor has been deprecated and replaced with {@link #AbstractServiceImpl(String, HomekitAccessory)}.
* Usages of this constructor will need to manually configure {@link Name} characteristic and
* {@link BatteryLevelCharacteristic} if needed.
* This constructor has been deprecated and replaced with
* {@link #AbstractServiceImpl(String, HomekitAccessory, String)}. Usages of
* this constructor will need to manually configure {@link Name} characteristic
* and {@link BatteryLevelCharacteristic} if needed.
*
* @param type unique UUID of the service. This information can be obtained from HomeKit Accessory Simulator.
*/
*/
@Deprecated
public AbstractServiceImpl(String type) {
this(type, null);
this(type, null, null);
}

/**
Expand All @@ -39,13 +40,14 @@ public AbstractServiceImpl(String type) {
*
* @param type unique UUID of the service. This information can be obtained from HomeKit Accessory Simulator.
* @param accessory HomeKit accessory exposed as a service.
* @param serviceName name of the service. This information is usually the name of the accessory.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we should leave the old constructor. Not necessarily for API compatibility, but because I think most use cases would probably just use the accessory name. The old constructor can just call the new one with accessory.getLabel()

Copy link
Collaborator

Choose a reason for hiding this comment

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

Which, granted, wouldn't be called in any of the framework provided services - what you did with the constructors there makes sense. But still, people implementing their own services would likely find it convenient.

*/
public AbstractServiceImpl(String type, HomekitAccessory accessory) {
public AbstractServiceImpl(String type, HomekitAccessory accessory, String serviceName) {
this.type = type;

if (accessory != null) {
// Add name characteristic
addCharacteristic(new Name(accessory));
addCharacteristic(new Name(serviceName));

// If battery operated accessory then add BatteryLevelCharacteristic
if (accessory instanceof BatteryAccessory) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
public class AccessoryInformationService extends AbstractServiceImpl {

public AccessoryInformationService(HomekitAccessory accessory) throws Exception {
super("0000003E-0000-1000-8000-0026BB765291", accessory);
this(accessory, accessory.getLabel());
}

public AccessoryInformationService(HomekitAccessory accessory, String serviceName) throws Exception {
super("0000003E-0000-1000-8000-0026BB765291", accessory, serviceName);
addCharacteristic(new Manufacturer(accessory));
addCharacteristic(new Model(accessory));
addCharacteristic(new SerialNumber(accessory));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
public class CarbonMonoxideSensorService extends AbstractServiceImpl {

public CarbonMonoxideSensorService(CarbonMonoxideSensor carbonMonoxideSensor) {
super("0000007F-0000-1000-8000-0026BB765291", carbonMonoxideSensor);
this(carbonMonoxideSensor, carbonMonoxideSensor.getLabel());
}

public CarbonMonoxideSensorService(CarbonMonoxideSensor carbonMonoxideSensor, String serviceName) {
super("0000007F-0000-1000-8000-0026BB765291", carbonMonoxideSensor, serviceName);
addCharacteristic(new CarbonMonoxideDetectedCharacteristic(carbonMonoxideSensor));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
public class ContactSensorService extends AbstractServiceImpl {

public ContactSensorService(ContactSensor contactSensor) {
super("00000080-0000-1000-8000-0026BB765291", contactSensor);
this(contactSensor, contactSensor.getLabel());
}

public ContactSensorService(ContactSensor contactSensor, String serviceName) {
super("00000080-0000-1000-8000-0026BB765291", contactSensor, serviceName);
addCharacteristic(new ContactSensorStateCharacteristic(contactSensor));
}
}
6 changes: 5 additions & 1 deletion src/main/java/com/beowulfe/hap/impl/services/FanService.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
public class FanService extends AbstractServiceImpl {

public FanService(Fan fan) {
super("00000040-0000-1000-8000-0026BB765291", fan);
this(fan, fan.getLabel());
}

public FanService(Fan fan, String serviceName) {
super("00000040-0000-1000-8000-0026BB765291", fan, serviceName);
addCharacteristic(new PowerStateCharacteristic(
() -> fan.getFanPower(),
v -> fan.setFanPower(v),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
public class GarageDoorService extends AbstractServiceImpl {

public GarageDoorService(GarageDoor door) {
super("00000041-0000-1000-8000-0026BB765291", door);
this(door, door.getLabel());
}

public GarageDoorService(GarageDoor door, String serviceName) {
super("00000041-0000-1000-8000-0026BB765291", door, serviceName);
addCharacteristic(new CurrentDoorStateCharacteristic(door));
addCharacteristic(new TargetDoorStateCharacteristic(door));
addCharacteristic(new ObstructionDetectedCharacteristic(() -> door.getObstructionDetected(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
public class HumiditySensorService extends AbstractServiceImpl {

public HumiditySensorService(HumiditySensor sensor) {
super("00000082-0000-1000-8000-0026BB765291", sensor);
this(sensor, sensor.getLabel());
}

public HumiditySensorService(HumiditySensor sensor, String serviceName) {
super("00000082-0000-1000-8000-0026BB765291", sensor, serviceName);
addCharacteristic(new CurrentRelativeHumidityCharacteristic(sensor));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.beowulfe.hap.impl.services;

import com.beowulfe.hap.accessories.LightSensor;
import com.beowulfe.hap.impl.characteristics.light.AmbientLightLevelCharacteristic;

public class LightSensorService extends AbstractServiceImpl {

public LightSensorService(LightSensor lightSensor) {
this(lightSensor, lightSensor.getLabel());
}

public LightSensorService(LightSensor lightSensor, String serviceName) {
super("00000084-0000-1000-8000-0026BB765291", lightSensor, serviceName);
addCharacteristic(new AmbientLightLevelCharacteristic(lightSensor));
}
}
Loading