[Senec] Fix for Senec firmware update (#15535)

* Fix for Senec update

Signed-off-by: querdenker2k <querdenker2k@gmx.de>
This commit is contained in:
Robert D
2023-11-11 14:01:37 +01:00
committed by GitHub
parent 6176b080c4
commit 1eacf67f34
10 changed files with 84 additions and 68 deletions

View File

@@ -13,7 +13,6 @@
package org.openhab.binding.senechome.internal;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
@@ -33,19 +32,17 @@ import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.stream.MalformedJsonException;
/**
* The {@link SenecHomeApi} class configures http client and
* performs status requests
*
* @author Steven Schwarznau - Initial contribution
* @author Robert Delbrück - Update for Senec API changes
*
*/
@NonNullByDefault
public class SenecHomeApi {
private static final String HTTP_PROTO_PREFIX = "http://";
private final Logger logger = LoggerFactory.getLogger(SenecHomeApi.class);
private final HttpClient httpClient;
private final Gson gson = new Gson();
@@ -66,28 +63,33 @@ public class SenecHomeApi {
* To receive new values, just modify the Json objects and add them to the thing channels
*
* @return Instance of SenecHomeResponse
* @throws MalformedURLException Configuration/URL is wrong
* @throws TimeoutException Communication failed (Timeout)
* @throws ExecutionException Communication failed
* @throws IOException Communication failed
* @throws InterruptedException Communication failed (Interrupted)
* @throws JsonSyntaxException Received response has an invalid json syntax
*/
public SenecHomeResponse getStatistics()
throws InterruptedException, TimeoutException, ExecutionException, IOException {
String location = HTTP_PROTO_PREFIX + hostname;
throws TimeoutException, ExecutionException, IOException, InterruptedException, JsonSyntaxException {
String location = hostname + "/lala.cgi";
logger.trace("sending request to: {}", location);
Request request = httpClient.newRequest(location);
request.header(HttpHeader.ACCEPT, MimeTypes.Type.APPLICATION_JSON.asString());
request.header(HttpHeader.CONTENT_TYPE, MimeTypes.Type.FORM_ENCODED.asString());
request.header(HttpHeader.CONTENT_TYPE, MimeTypes.Type.APPLICATION_JSON.asString());
ContentResponse response = null;
try {
response = request.method(HttpMethod.POST)
.content(new StringContentProvider(gson.toJson(new SenecHomeResponse()))).send();
String dataToSend = gson.toJson(new SenecHomeResponse());
logger.trace("data to send: {}", dataToSend);
response = request.method(HttpMethod.POST).content(new StringContentProvider(dataToSend)).send();
if (response.getStatus() == HttpStatus.OK_200) {
return Objects.requireNonNull(gson.fromJson(response.getContentAsString(), SenecHomeResponse.class));
String responseString = response.getContentAsString();
return Objects.requireNonNull(gson.fromJson(responseString, SenecHomeResponse.class));
} else {
logger.trace("Got unexpected response code {}", response.getStatus());
throw new IOException("Got unexpected response code " + response.getStatus());
}
} catch (MalformedJsonException | JsonSyntaxException | InterruptedException | TimeoutException
| ExecutionException e) {
} catch (JsonSyntaxException | InterruptedException | TimeoutException | ExecutionException e) {
String errorMessage = "\nlocation: " + location;
errorMessage += "\nrequest: " + request.toString();
errorMessage += "\nrequest.getHeaders: " + request.getHeaders();

View File

@@ -23,7 +23,7 @@ import org.openhab.core.thing.ThingTypeUID;
*/
@NonNullByDefault
public class SenecHomeBindingConstants {
private static final String BINDING_ID = "senechome";
protected static final String BINDING_ID = "senechome";
private static final String THING_BASE_ID = "senechome";
public static final ThingTypeUID THING_TYPE_SENEC_HOME_BATTERY = new ThingTypeUID(BINDING_ID, THING_BASE_ID);
@@ -65,15 +65,6 @@ public class SenecHomeBindingConstants {
public static final String CHANNEL_SENEC_GRID_VOLTAGE_PH3 = "gridVoltagePhase3";
public static final String CHANNEL_SENEC_GRID_FREQUENCY = "gridFrequency";
// SenecHomeStatistics
public static final String CHANNEL_SENEC_LIVE_BAT_CHARGE = "liveBatCharge";
public static final String CHANNEL_SENEC_LIVE_BAT_DISCHARGE = "liveBatDischarge";
public static final String CHANNEL_SENEC_LIVE_GRID_IMPORT = "liveGridImport";
public static final String CHANNEL_SENEC_LIVE_GRID_EXPORT = "liveGridExport";
public static final String CHANNEL_SENEC_LIVE_HOUSE_CONSUMPTION = "liveHouseConsumption";
public static final String CHANNEL_SENEC_LIVE_POWER_GENERATOR = "livePowerGenerator";
public static final String CHANNEL_SENEC_LIVE_ENERGY_WALLBOX1 = "liveEnergyWallbox1";
// SenecHomeBattery
public static final String CHANNEL_SENEC_CHARGED_ENERGY_PACK1 = "chargedEnergyPack1";
public static final String CHANNEL_SENEC_CHARGED_ENERGY_PACK2 = "chargedEnergyPack2";

View File

@@ -16,10 +16,12 @@ package org.openhab.binding.senechome.internal;
* The {@link SenecHomeConfigurationDTO} class contains fields mapping thing configuration parameters.
*
* @author Steven Schwarznau - Initial contribution
* @author Robert Delbrück - Add useHttp
*/
public class SenecHomeConfigurationDTO {
public String hostname;
public int refreshInterval = 15;
public int limitationTresholdValue = 95;
public int limitationDuration = 120;
public boolean useHttp = false;
}

View File

@@ -124,7 +124,7 @@ public class SenecHomeHandler extends BaseThingHandler {
@Override
public void initialize() {
config = getConfigAs(SenecHomeConfigurationDTO.class);
senecHomeApi.setHostname(config.hostname);
senecHomeApi.setHostname("%s://%s".formatted(config.useHttp ? "http" : "https", config.hostname));
refreshJob = scheduler.scheduleWithFixedDelay(this::refresh, 0, config.refreshInterval, TimeUnit.SECONDS);
limitationStatus = null;
}
@@ -197,20 +197,6 @@ public class SenecHomeHandler extends BaseThingHandler {
updateQtyState(CHANNEL_SENEC_GRID_VOLTAGE_PH3, response.grid.currentGridVoltagePerPhase[2], 2, Units.VOLT);
updateQtyState(CHANNEL_SENEC_GRID_FREQUENCY, response.grid.currentGridFrequency, 2, Units.HERTZ);
updateQtyState(CHANNEL_SENEC_LIVE_BAT_CHARGE, response.statistics.liveBatCharge, 2, Units.KILOWATT_HOUR);
updateQtyState(CHANNEL_SENEC_LIVE_BAT_DISCHARGE, response.statistics.liveBatDischarge, 2,
Units.KILOWATT_HOUR);
updateQtyState(CHANNEL_SENEC_LIVE_GRID_IMPORT, response.statistics.liveGridImport, 2, Units.KILOWATT_HOUR);
updateQtyState(CHANNEL_SENEC_LIVE_GRID_EXPORT, response.statistics.liveGridExport, 2, Units.KILOWATT_HOUR);
updateQtyState(CHANNEL_SENEC_LIVE_HOUSE_CONSUMPTION, response.statistics.liveHouseConsumption, 2,
Units.KILOWATT_HOUR);
updateQtyState(CHANNEL_SENEC_LIVE_POWER_GENERATOR, response.statistics.livePowerGenerator, 2,
Units.KILOWATT_HOUR);
if (response.statistics.liveWallboxEnergy != null) {
updateQtyState(CHANNEL_SENEC_LIVE_ENERGY_WALLBOX1, response.statistics.liveWallboxEnergy[0], 2,
Units.KILOWATT_HOUR, DIVISOR_ISO_TO_KILO);
}
if (response.battery.chargedEnergy != null) {
updateQtyState(CHANNEL_SENEC_CHARGED_ENERGY_PACK1, response.battery.chargedEnergy[0], 2,
Units.KILOWATT_HOUR, DIVISOR_MILLI_TO_KILO);

View File

@@ -17,15 +17,19 @@ import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.openhab.core.io.net.http.HttpClientFactory;
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.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link SenecHomeHandlerFactory} is responsible for creating things and thing
@@ -36,15 +40,17 @@ import org.osgi.service.component.annotations.Reference;
@NonNullByDefault
@Component(configurationPid = "binding.senechome", service = ThingHandlerFactory.class)
public class SenecHomeHandlerFactory extends BaseThingHandlerFactory {
private final Logger logger = LoggerFactory.getLogger(SenecHomeHandlerFactory.class);
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set
.of(SenecHomeBindingConstants.THING_TYPE_SENEC_HOME_BATTERY);
private HttpClient httpClient;
private final HttpClient httpClient;
@Activate
public SenecHomeHandlerFactory(@Reference HttpClientFactory httpClientFactory) {
this.httpClient = httpClientFactory.getCommonHttpClient();
SslContextFactory.Client sslContextFactory = new SslContextFactory.Client(true); // Accept all certificates
this.httpClient = httpClientFactory.createHttpClient(SenecHomeBindingConstants.BINDING_ID, sslContextFactory);
}
@Override
@@ -62,4 +68,26 @@ public class SenecHomeHandlerFactory extends BaseThingHandlerFactory {
return null;
}
@Override
protected void activate(ComponentContext componentContext) {
super.activate(componentContext);
try {
httpClient.start();
} catch (Exception e) {
logger.warn("cannot start Jetty-Http-Client", e);
}
}
@Override
protected void deactivate(ComponentContext componentContext) {
super.deactivate(componentContext);
try {
httpClient.stop();
} catch (Exception e) {
logger.warn("cannot stop Jetty-Http-Client", e);
}
}
}

View File

@@ -28,14 +28,13 @@ public class SenecHomeResponse implements Serializable {
public @SerializedName("PV1") SenecHomePower power = new SenecHomePower();
public @SerializedName("ENERGY") SenecHomeEnergy energy = new SenecHomeEnergy();
public @SerializedName("PM1OBJ1") SenecHomeGrid grid = new SenecHomeGrid();
public @SerializedName("STATISTIC") SenecHomeStatistics statistics = new SenecHomeStatistics();
public @SerializedName("BMS") SenecHomeBattery battery = new SenecHomeBattery();
public @SerializedName("TEMPMEASURE") SenecHomeTemperature temperature = new SenecHomeTemperature();
public @SerializedName("WALLBOX") SenecHomeWallbox wallbox = new SenecHomeWallbox();
@Override
public String toString() {
return "SenecHomeResponse [power=" + power + ", energy=" + energy + ", grid=" + grid + ", statistics="
+ statistics + "battery" + battery + "temperature" + temperature + "wallbox" + wallbox + "]";
return "SenecHomeResponse [power=" + power + ", energy=" + energy + ", grid=" + grid + ", battery" + battery
+ "temperature" + temperature + "wallbox" + wallbox + "]";
}
}

View File

@@ -18,6 +18,8 @@ thing-type.config.senechome.senechome.limitationTresholdValue.label = Limitation
thing-type.config.senechome.senechome.limitationTresholdValue.description = Treshold in percent, defines when limitation state is enabled
thing-type.config.senechome.senechome.refreshInterval.label = Refresh Interval
thing-type.config.senechome.senechome.refreshInterval.description = Rate of refreshing details (in s)
thing-type.config.senechome.senechome.useHttp.label = Use HTTP
thing-type.config.senechome.senechome.useHttp.description = Use legacy http access instead of https
# channel types

View File

@@ -48,15 +48,6 @@
<channel id="gridVoltagePhase3" typeId="gridVoltagePhase3"/>
<channel id="gridFrequency" typeId="gridFrequency"/>
<!-- SenecHomeStatistics -->
<channel id="liveBatCharge" typeId="liveBatCharge"/>
<channel id="liveBatDischarge" typeId="liveBatDischarge"/>
<channel id="liveGridImport" typeId="liveGridImport"/>
<channel id="liveGridExport" typeId="liveGridExport"/>
<channel id="liveHouseConsumption" typeId="liveHouseConsumption"/>
<channel id="livePowerGenerator" typeId="livePowerGenerator"/>
<channel id="liveEnergyWallbox1" typeId="liveEnergyWallbox1"/>
<!-- SenecHomeBattery -->
<channel id="chargedEnergyPack1" typeId="chargedEnergyPack1"/>
<channel id="chargedEnergyPack2" typeId="chargedEnergyPack2"/>
@@ -101,6 +92,10 @@
<channel id="wallbox1ChargingPower" typeId="wallbox1ChargingPower"/>
</channels>
<properties>
<property name="thingTypeVersion">1</property>
</properties>
<config-description>
<parameter name="hostname" type="text" required="true">
<label>Hostname/IP Address</label>
@@ -122,6 +117,11 @@
<description>Duration of stable values until state is changed, defined in seconds</description>
<default>120</default>
</parameter>
<parameter name="useHttp" type="boolean" required="false">
<label>Use HTTP</label>
<description>Use legacy http access instead of https</description>
<default>false</default>
</parameter>
</config-description>
</thing-type>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<update:update-descriptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:update="https://openhab.org/schemas/update-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/update-description/v1.0.0 https://openhab.org/schemas/update-description-1.0.0.xsd">
<thing-type uid="senechome:senechome">
<instruction-set targetVersion="1">
<remove-channel id="liveBatCharge"/>
<remove-channel id="liveBatDischarge"/>
<remove-channel id="liveGridImport"/>
<remove-channel id="liveGridExport"/>
<remove-channel id="liveHouseConsumption"/>
<remove-channel id="livePowerGenerator"/>
<remove-channel id="liveEnergyWallbox1"/>
</instruction-set>
</thing-type>
</update:update-descriptions>