Skip to content

Commit

Permalink
Ready for pull request
Browse files Browse the repository at this point in the history
Signed-off-by: Jeff James <[email protected]>
  • Loading branch information
jsjames committed Feb 9, 2025
1 parent 077e9c3 commit 2575bb9
Show file tree
Hide file tree
Showing 10 changed files with 182 additions and 98 deletions.
1 change: 1 addition & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@
/bundles/org.openhab.binding.sensebox/ @hakan42
/bundles/org.openhab.binding.sensibo/ @seime
/bundles/org.openhab.binding.sensorcommunity/ @weymann
/bundles/org.openhab.binding.senseenergy/ @jsjames
/bundles/org.openhab.binding.serial/ @MikeJMajor
/bundles/org.openhab.binding.serialbutton/ @kaikreuzer
/bundles/org.openhab.binding.shelly/ @markus7017
Expand Down
93 changes: 52 additions & 41 deletions bundles/org.openhab.binding.senseenergy/README.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
public class SenseEnergyDatagram {

private final Logger logger = LoggerFactory.getLogger(SenseEnergyDatagram.class);
static private final int BUFFERSIZE = 1024;
private static final int BUFFERSIZE = 1024;

private @Nullable DatagramSocket datagramSocket;
private @Nullable SenseEnergyDatagramListener packetListener;
Expand Down Expand Up @@ -124,11 +124,11 @@ public void run() {
while (connected) {
try {
localSocket.receive(packet);
} catch (IOException exception) {
logger.debug("Exception during packet read - {}", exception.getMessage());
} catch (IOException e) {
logger.debug("Exception during packet read - {}", e.getMessage());
try {
Thread.sleep(100); // allow CPU to breath
} catch (InterruptedException e) {
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
break;
Expand Down Expand Up @@ -162,7 +162,6 @@ public void run() {

public void sendResponse(SocketAddress socketAddress, SenseEnergyDatagramGetSysInfo getSysInfo,
SenseEnergyDatagramGetRealtime getRealtime) throws IOException {

String jsonResponse = String.format("{\"emeter\":{\"get_realtime\":%s},\"system\":{\"get_sysinfo\":%s}}",
gson.toJson(getRealtime), gson.toJson(getSysInfo));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

import static org.openhab.binding.senseenergy.internal.SenseEnergyBindingConstants.HEARTBEAT_MINUTES;
import static org.openhab.binding.senseenergy.internal.SenseEnergyBindingConstants.MONITOR_THING_TYPE;
import static org.openhab.binding.senseenergy.internal.SenseEnergyBindingConstants.PROXY_DEVICE_THING_TYPE;

import java.util.Collection;
import java.util.Collections;
Expand Down Expand Up @@ -172,17 +171,6 @@ public SenseEnergyMonitorHandler getMonitorHandler(long id) {
.orElse(null); //
}

@Nullable
public SenseEnergyProxyDeviceHandler getProxyDeviceByMAC(String macAddress) {
return getThing().getThings().stream() //
.filter(t -> t.getThingTypeUID().equals(PROXY_DEVICE_THING_TYPE)) //
.map(t -> (SenseEnergyProxyDeviceHandler) t.getHandler()) //
.filter(Objects::nonNull) //
.filter(h -> h.getMAC().equals(macAddress)) //
.findFirst() //
.orElse(null);
}

/*
* rediscover the monitors again to add any back to inbox
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,11 @@ public class SenseEnergyMonitorHandler extends BaseBridgeHandler
implements SenseEnergyWebSocketListener, SenseEnergyDatagramListener {
private final Logger logger = LoggerFactory.getLogger(SenseEnergyMonitorHandler.class);

static final private int MAX_RESPONSES_PER_REQUEST = 5;
static final private int SENSE_DATAGRAM_BCAST_PORT = 9999;
private static final int MAX_RESPONSES_PER_REQUEST = 5;
private static final int SENSE_DATAGRAM_BCAST_PORT = 9999;

static final private String CHANNEL_PROPERTY_ID = "sense-id";
static final private String CHANNEL_PROPERTY_LABEL = "sense-label";
private static final String CHANNEL_PROPERTY_ID = "sense-id";
private static final String CHANNEL_PROPERTY_LABEL = "sense-label";

private long id;
@Nullable
Expand Down Expand Up @@ -370,12 +370,7 @@ private DeviceType deduceDeviceType(SenseEnergyApiDevice apiDevice) {
return DeviceType.DISCOVERED_DEVICE;
}

SenseEnergyBridgeHandler bridgeHandler = getBridgeHandler();
if (bridgeHandler == null) {
throw new IllegalStateException("Bridge handler is not available");
}

SenseEnergyProxyDeviceHandler proxyHandler = bridgeHandler.getProxyDeviceByMAC(apiDevice.tags.deviceID);
SenseEnergyProxyDeviceHandler proxyHandler = getProxyDeviceByMAC(apiDevice.tags.deviceID);
return (proxyHandler != null) ? DeviceType.PROXY_DEVICE : DeviceType.SELF_REPORTING_DEVICE;
}

Expand Down Expand Up @@ -547,7 +542,6 @@ public void updateChannel(String channelGroup, String channel, float value, Unit
* @param thingStatus
*/
public void childStatusChange(SenseEnergyProxyDeviceHandler proxyDeviceHandler, ThingStatus thingStatus) {

if (thingStatus == ThingStatus.ONLINE && getThing().getStatus() != ThingStatus.ONLINE) {
throw new IllegalStateException("Child should never go ONLINE w/o the bridge being online");
}
Expand Down Expand Up @@ -690,14 +684,14 @@ public void updateDiscoveredDevicesStatus(SenseEnergyWebSocketDevice[] devices)
reconcileDiscoveredDeviceChannels(null);
}

DeviceType deviceType = senseDevicesType.getOrDefault(device.id, DeviceType.DISCOVERED_DEVICE);

// Send trigger if device just turned on
if (!this.devicesOn.contains(device.id)) {
DeviceType deviceType = senseDevicesType.getOrDefault(device.id, DeviceType.DISCOVERED_DEVICE);
triggerChannel(makeDeviceChannelUID(deviceType, device.id, CHANNEL_DEVICE_TRIGGER), "ON");
logger.trace("Discovered device turned on: {}({})", device.name, device.id);
}

DeviceType deviceType = senseDevicesType.getOrDefault(device.id, DeviceType.DISCOVERED_DEVICE);
ChannelUID channelUID = makeDeviceChannelUID(deviceType, device.id, CHANNEL_DEVICE_POWER);
if (isLinked(channelUID)) {
updateState(channelUID, new QuantityType<>(device.w, Units.WATT));
Expand All @@ -715,4 +709,15 @@ public void updateDiscoveredDevicesStatus(SenseEnergyWebSocketDevice[] devices)
}
this.devicesOn = updateDevicesOn;
}

@Nullable
public SenseEnergyProxyDeviceHandler getProxyDeviceByMAC(String macAddress) {
return getThing().getThings().stream() //
.filter(t -> t.getThingTypeUID().equals(PROXY_DEVICE_THING_TYPE)) //
.map(t -> (SenseEnergyProxyDeviceHandler) t.getHandler()) //
.filter(Objects::nonNull) //
.filter(h -> h.getMAC().equals(macAddress)) //
.findFirst() //
.orElse(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static org.openhab.binding.senseenergy.internal.SenseEnergyBindingConstants.CONFIG_PARAMETER_MAC;
import static org.openhab.binding.senseenergy.internal.SenseEnergyBindingConstants.CONFIG_PARAMETER_POWER_LEVELS;

import java.util.Arrays;
import java.util.HexFormat;
import java.util.Map;
import java.util.Objects;
Expand Down Expand Up @@ -59,11 +60,11 @@
public class SenseEnergyProxyDeviceHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(SenseEnergyProxyDeviceHandler.class);

static final private byte[] OUI = new byte[] { 0x53, 0x75, 0x31 };
static final private String PROXY_DEVICE_SW_VERSION = "1.2.5 Build 171206 Rel.085954";
static final private String PROXY_DEVICE_HW_VERSION = "1.0";
static final private String PROXY_DEVICE_TYPE = "IOT.SMARTPLUGSWITCH";
static final private String PROXY_DEVICE_MODEL = "HS110(US)";
private static final byte[] OUI = new byte[] { 0x53, 0x75, 0x31 };
private static final String PROXY_DEVICE_SW_VERSION = "1.2.5 Build 171206 Rel.085954";
private static final String PROXY_DEVICE_HW_VERSION = "1.0";
private static final String PROXY_DEVICE_TYPE = "IOT.SMARTPLUGSWITCH";
private static final String PROXY_DEVICE_MODEL = "HS110(US)";

private SenseEnergyProxyDeviceConfiguration config = new SenseEnergyProxyDeviceConfiguration();

Expand All @@ -87,7 +88,7 @@ public void initialize() {
byte[] mac = randomizeMAC(OUI);

String macAddress = HexFormat.of().withDelimiter(":").formatHex(mac).toUpperCase();
logger.trace("Spoof MAC address: {}", macAddress);
logger.debug("Spoof MAC address: {}", macAddress);

selfConfigurationChange = true;
c = this.editConfiguration();
Expand Down Expand Up @@ -293,10 +294,9 @@ public byte[] randomizeMAC(byte @Nullable [] oui) {
}

if (oui != null) {
for (int i = 0; i < oui.length; i++) {
macAddress[i] = oui[i];
}
macAddress = Arrays.copyOf(oui, oui.length);
}

return macAddress;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,9 @@ public String toString() {
@Nullable
public QuantityType<Power> getLevel(int level) {
int numNodes = powerValueLevels.size();
if (numNodes == 0)
if (numNodes == 0) {
return null;
}

Point2D.Float p0 = new Point2D.Float(0, 0);
Point2D.Float p1 = new Point2D.Float(100, getPowerFloatValue(numNodes - 1)); // if only one node, value is set
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,17 @@
*/
@NonNullByDefault
public class TpLinkEncryption {
static final private int STARTKEY = 0xAB;

static public byte[] encrypt(String unencrypted) {
private static final int STARTKEY = 0xAB;

public static byte[] encrypt(String unencrypted) {
try {
return encrypt(unencrypted.getBytes("UTF-8"), unencrypted.length());
} catch (UnsupportedEncodingException e) {
return new byte[0];
}
}

static public byte[] encrypt(byte[] unencrypted, int l) {
public static byte[] encrypt(byte[] unencrypted, int l) {
int length = (l == 0) ? unencrypted.length : l;
int key = STARTKEY;

Expand All @@ -48,7 +47,7 @@ static public byte[] encrypt(byte[] unencrypted, int l) {
return encrypted;
}

static public byte[] decrypt(byte[] crypted, int l) {
public static byte[] decrypt(byte[] crypted, int l) {
int key = STARTKEY;
int a;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,83 @@
# FIXME: please add all English translations to this file so the texts can be translated using Crowdin
# FIXME: to generate the content of this file run: mvn i18n:generate-default-translations
# FIXME: see also: https://www.openhab.org/docs/developer/utils/i18n.html
# add-on

addon.senseenergy.name = SenseEnergy Binding
addon.senseenergy.description = This is the binding for Sense energy monitor (sense.com).

# thing types

thing-type.senseenergy.cloud-connector.label = Sense Energy Cloud Connector
thing-type.senseenergy.cloud-connector.description = The Sense Home cloud connector establishes connection to the Sense cloud API and services.
thing-type.senseenergy.monitor.label = Sense Energy Monitor
thing-type.senseenergy.monitor.description = Sense energy monitor instance.
thing-type.senseenergy.proxy-device.label = Proxy Device
thing-type.senseenergy.proxy-device.description = A proxy device to notifiy the sense monitor of real-time power draw. All channels are "one-way" in that they only report their settings to Sense.

# thing types config

thing-type.config.senseenergy.cloud-connector.email.label = Email
thing-type.config.senseenergy.cloud-connector.email.description = Sense account email address
thing-type.config.senseenergy.cloud-connector.password.label = Password
thing-type.config.senseenergy.cloud-connector.password.description = Sense account password
thing-type.config.senseenergy.monitor.id.label = ID
thing-type.config.senseenergy.monitor.id.description = Device ID (only known from the openHAB log or when devices is discovered).
thing-type.config.senseenergy.proxy-device.macAddress.label = Spoof'd MAC Address
thing-type.config.senseenergy.proxy-device.macAddress.description = A spoof'ed MAC address for this proxy device.
thing-type.config.senseenergy.proxy-device.powerLevels.label = Power Levels
thing-type.config.senseenergy.proxy-device.powerLevels.description = Power levels for different states. Examples: "5W" (static full ON power), ".2W, 5W" (for static power range), "OFF=.2W, LOW=2W, HIGH=5W" (for static power in different states), ".2,2W,2.5W,3W" (for non-linear dimmer rage".
thing-type.config.senseenergy.proxy-device.senseName.label = Sense Name
thing-type.config.senseenergy.proxy-device.senseName.description = Name of device to be used by Sense.
thing-type.config.senseenergy.proxy-device.voltage.label = Voltage
thing-type.config.senseenergy.proxy-device.voltage.description = Supply voltage for device.

# channel group types

channel-group-type.senseenergy.discovered-devices.label = Discovered Devices
channel-group-type.senseenergy.discovered-devices.description = Sense discovered devices
channel-group-type.senseenergy.general.label = General Information
channel-group-type.senseenergy.general.description = General information about the monitor
channel-group-type.senseenergy.proxy-devices.label = Proxy Devices
channel-group-type.senseenergy.proxy-devices.description = Proxy devices configured in openHAB which report their power
channel-group-type.senseenergy.self-reporting-devices.label = Self-Reporting Devices
channel-group-type.senseenergy.self-reporting-devices.description = Devices that self report their power to Sense

# channel types

channel-type.senseenergy.device-power.label = Power
channel-type.senseenergy.device-power.description = Power draw of discovered device.
channel-type.senseenergy.device-trigger.label = On Off Trigger
channel-type.senseenergy.device-trigger.description = Triggered when the discovered device turns ON and OFF.
channel-type.senseenergy.devices-updated-trigger.label = Discovered Devices Updated
channel-type.senseenergy.devices-updated-trigger.description = Triggered when the discovered device list has been updated
channel-type.senseenergy.frequency.label = Frequency
channel-type.senseenergy.frequency.description = Electrical frequency detected by Sense.
channel-type.senseenergy.grid-power.label = Grid Power
channel-type.senseenergy.grid-power.description = Power consumed from the grid (negative if supplying power to grid)
channel-type.senseenergy.leg-1-power.label = Leg 1 Power
channel-type.senseenergy.leg-1-power.description = Power detected by the first Sense clamp.
channel-type.senseenergy.leg-2-power.label = Leg 2 Power
channel-type.senseenergy.leg-2-power.description = Power detected by the second Sense clamp.
channel-type.senseenergy.main-power.label = Main Power
channel-type.senseenergy.main-power.description = Power detected by the main Sense clamp.
channel-type.senseenergy.potential-1.label = Potential 1
channel-type.senseenergy.potential-1.description = Potential measured on first 120V branch.
channel-type.senseenergy.potential-2.label = Potential 2
channel-type.senseenergy.potential-2.description = Potential measured on second 120V branch.
channel-type.senseenergy.proxy-device-dimmer.label = Device Dimmer
channel-type.senseenergy.proxy-device-dimmer.description = Dimmer to notify the current power. This will report to sense an interpolated value based on the specified levels.
channel-type.senseenergy.proxy-device-power.label = Power Level
channel-type.senseenergy.proxy-device-power.description = Realtime power to send to Sense. Note, if you are using the Switch, Dimmer or State channels, it is not necessary to use this channel.
channel-type.senseenergy.proxy-device-state.label = Device State
channel-type.senseenergy.proxy-device-state.description = Current device state. This will report to sense the specified power based on the device state.
channel-type.senseenergy.proxy-device-switch.label = Device Switch
channel-type.senseenergy.proxy-device-switch.description = OnOff switch to notify when device is On/Off. This will report to sense the full ON or full OFF values specified.
channel-type.senseenergy.solar-power.label = Solar Power
channel-type.senseenergy.solar-power.description = Power detected by the solar Sense clamp.

# thing status messages
offline.configuration-error.bridge-missing = Sense Cloud Connector bridge must be online

# api error conditions
api.invalid-user-credentials = Invalid user credentials, please check configuration
api.response-fail = API response fail
api.response-invalid = API response invalid
api.rate-limit-exceeded = API rate limit exceeded
Original file line number Diff line number Diff line change
Expand Up @@ -81,49 +81,49 @@
</channel-group-type>

<channel-type id="potential-1">
<item-type>Number:ElectricPotential</item-type>
<item-type unitHint="V">Number:ElectricPotential</item-type>
<label>Potential 1</label>
<description>Potential measured on first 120V branch.</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>

<channel-type id="potential-2">
<item-type>Number:ElectricPotential</item-type>
<item-type unitHint="V">Number:ElectricPotential</item-type>
<label>Potential 2</label>
<description>Potential measured on second 120V branch.</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>

<channel-type id="leg-1-power">
<item-type>Number:Power</item-type>
<item-type unitHint="W">Number:Power</item-type>
<label>Leg 1 Power</label>
<description>Power detected by the first Sense clamp.</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>

<channel-type id="leg-2-power">
<item-type>Number:Power</item-type>
<item-type unitHint="W">Number:Power</item-type>
<label>Leg 2 Power</label>
<description>Power detected by the second Sense clamp.</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>

<channel-type id="main-power">
<item-type>Number:Power</item-type>
<item-type unitHint="W">Number:Power</item-type>
<label>Main Power</label>
<description>Power detected by the main Sense clamp.</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>

<channel-type id="solar-power">
<item-type>Number:Power</item-type>
<item-type unitHint="W">Number:Power</item-type>
<label>Solar Power</label>
<description>Power detected by the solar Sense clamp.</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>

<channel-type id="grid-power">
<item-type>Number:Power</item-type>
<item-type unitHint="W">Number:Power</item-type>
<label>Grid Power</label>
<description>Power consumed from the grid (negative if supplying power to grid)</description>
<state readOnly="true" pattern="%.1f %unit%"/>
Expand All @@ -136,7 +136,7 @@
</channel-type>

<channel-type id="device-power">
<item-type>Number:Power</item-type>
<item-type unitHint="W">Number:Power</item-type>
<label>Power</label>
<description>Power draw of discovered device.</description>
<state readOnly="true" pattern="%.1f %unit%"/>
Expand All @@ -155,7 +155,7 @@
</channel-type>

<channel-type id="frequency" advanced="true">
<item-type>Number:Frequency</item-type>
<item-type unitHint="Hz">Number:Frequency</item-type>
<label>Frequency</label>
<description>Electrical frequency detected by Sense.</description>
<state readOnly="true" pattern="%.1f %unit%"/>
Expand Down

0 comments on commit 2575bb9

Please sign in to comment.