diff --git a/backend/pom.xml b/backend/pom.xml index 4f8294e5a3a..2ba151c6933 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -5,7 +5,7 @@ http://openems.io io.openems edge - 1.7.1 + 2018.1 jar https://github.com/OpenEMS/openems diff --git a/common/.classpath b/common/.classpath index 70e13502765..a4379df1766 100644 --- a/common/.classpath +++ b/common/.classpath @@ -10,18 +10,6 @@ - - - - - - - - - - - - diff --git a/common/pom.xml b/common/pom.xml index b8a0378d7b8..c634bbe3c82 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -5,7 +5,7 @@ http://openems.io io.openems common - 1.7.1 + 2018. jar https://github.com/OpenEMS/openems diff --git a/common/src/io/openems/common/types/ChannelEnum.java b/common/src/io/openems/common/types/ChannelEnum.java new file mode 100644 index 00000000000..91112c17bbd --- /dev/null +++ b/common/src/io/openems/common/types/ChannelEnum.java @@ -0,0 +1,9 @@ +package io.openems.common.types; + +import java.util.Locale; + +public interface ChannelEnum { + int getValue(); + + String getName(Locale locale); +} diff --git a/common/src/io/openems/common/utils/JsonUtils.java b/common/src/io/openems/common/utils/JsonUtils.java index 124da550902..a866ea09b4c 100644 --- a/common/src/io/openems/common/utils/JsonUtils.java +++ b/common/src/io/openems/common/utils/JsonUtils.java @@ -1,337 +1,342 @@ -package io.openems.common.utils; - -import java.net.Inet4Address; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.Set; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.google.gson.JsonParser; -import com.google.gson.JsonPrimitive; - -import io.openems.common.exceptions.NotImplementedException; -import io.openems.common.exceptions.OpenemsException; - -// TODO use getAsOptional***() as basis for getAs***() to avoid unnecessary exceptions -public class JsonUtils { - public static JsonArray getAsJsonArray(JsonElement jElement) throws OpenemsException { - if (!jElement.isJsonArray()) { - throw new OpenemsException("This is not a JsonArray: " + jElement); - } - return jElement.getAsJsonArray(); - }; - - public static JsonArray getAsJsonArray(JsonElement jElement, String memberName) throws OpenemsException { - JsonElement jSubElement = getSubElement(jElement, memberName); - if (!jSubElement.isJsonArray()) { - throw new OpenemsException("Element [" + memberName + "] is not a JsonArray: " + jSubElement); - } - return jSubElement.getAsJsonArray(); - }; - - public static Optional getAsOptionalJsonArray(JsonElement jElement, String memberName) { - try { - return Optional.of(getAsJsonArray(jElement, memberName)); - } catch (OpenemsException e) { - return Optional.empty(); - } - } - - public static JsonObject getAsJsonObject(JsonElement jElement) throws OpenemsException { - if (!jElement.isJsonObject()) { - throw new OpenemsException("This is not a JsonObject: " + jElement); - } - return jElement.getAsJsonObject(); - }; - - public static JsonObject getAsJsonObject(JsonElement jElement, String memberName) throws OpenemsException { - JsonElement jsubElement = getSubElement(jElement, memberName); - if (!jsubElement.isJsonObject()) { - throw new OpenemsException("Element [" + memberName + "] is not a JsonObject: " + jsubElement); - } - return jsubElement.getAsJsonObject(); - }; - - public static Optional getAsOptionalJsonObject(JsonElement jElement, String memberName) { - try { - return Optional.of(getAsJsonObject(jElement, memberName)); - } catch (OpenemsException e) { - return Optional.empty(); - } - } - - public static JsonPrimitive getAsPrimitive(JsonElement jElement, String memberName) throws OpenemsException { - JsonElement jSubElement = getSubElement(jElement, memberName); - return getAsPrimitive(jSubElement); - } - - public static JsonPrimitive getAsPrimitive(JsonElement jElement) throws OpenemsException { - if (!jElement.isJsonPrimitive()) { - throw new OpenemsException("This is not a JsonPrimitive: " + jElement); - } - return jElement.getAsJsonPrimitive(); - } - - public static String getAsString(JsonElement jElement) throws OpenemsException { - JsonPrimitive jPrimitive = getAsPrimitive(jElement); - if (!jPrimitive.isString()) { - throw new OpenemsException("This is not a String: " + jPrimitive); - } - return jPrimitive.getAsString(); - } - - public static boolean getAsBoolean(JsonElement jElement) throws OpenemsException { - JsonPrimitive jPrimitive = getAsPrimitive(jElement); - if (!jPrimitive.isBoolean()) { - throw new OpenemsException("This is not a Boolean: " + jPrimitive); - } - return jPrimitive.getAsBoolean(); - } - - public static Optional getAsOptionalString(JsonElement jElement, String memberName) { - try { - return Optional.of(getAsString(jElement, memberName)); - } catch (OpenemsException e) { - return Optional.empty(); - } - } - - public static String getAsString(JsonElement jElement, String memberName) throws OpenemsException { - JsonPrimitive jPrimitive = getAsPrimitive(jElement, memberName); - if (!jPrimitive.isString()) { - throw new OpenemsException("Element [" + memberName + "] is not a String: " + jPrimitive); - } - return jPrimitive.getAsString(); - } - - public static Optional getAsOptionalInt(JsonElement jElement, String memberName) { - try { - return Optional.of(getAsInt(jElement, memberName)); - } catch (OpenemsException e) { - return Optional.empty(); - } - } - - public static Optional getAsOptionalLong(JsonElement jElement, String memberName) { - try { - return Optional.of(getAsLong(jElement, memberName)); - } catch (OpenemsException e) { - return Optional.empty(); - } - } - - public static int getAsInt(JsonElement jElement, String memberName) throws OpenemsException { - JsonPrimitive jPrimitive = getAsPrimitive(jElement, memberName); - if (jPrimitive.isNumber()) { - return jPrimitive.getAsInt(); - } else if (jPrimitive.isString()) { - String string = jPrimitive.getAsString(); - return Integer.parseInt(string); - } - throw new OpenemsException("Element [" + memberName + "] is not an Integer: " + jPrimitive); - } - - public static boolean getAsBoolean(JsonElement jElement, String memberName) throws OpenemsException { - JsonPrimitive jPrimitive = getAsPrimitive(jElement, memberName); - if (!jPrimitive.isBoolean()) { - throw new OpenemsException("Element [" + memberName + "] is not a Boolean: " + jPrimitive); - } - return jPrimitive.getAsBoolean(); - } - - /** - * Takes a json in the form 'YYYY-MM-DD' and converts it to a ZonedDateTime with - * hour, minute and second set to zero. - * - * @param jElement - * @param memberName - * @param timezone - * @return - * @throws OpenemsException - */ - public static ZonedDateTime getAsZonedDateTime(JsonElement jElement, String memberName, ZoneId timezone) - throws OpenemsException { - String[] date = JsonUtils.getAsString(jElement, memberName).split("-"); - try { - int year = Integer.valueOf(date[0]); - int month = Integer.valueOf(date[1]); - int day = Integer.valueOf(date[2]); - return ZonedDateTime.of(year, month, day, 0, 0, 0, 0, timezone); - } catch (ArrayIndexOutOfBoundsException e) { - throw new OpenemsException("Element [" + memberName + "] is not a Date: " + jElement + ". Error: " + e); - } - } - - public static long getAsLong(JsonElement jElement, String memberName) throws OpenemsException { - JsonPrimitive jPrimitive = getAsPrimitive(jElement, memberName); - if (jPrimitive.isNumber()) { - return jPrimitive.getAsLong(); - } else if (jPrimitive.isString()) { - String string = jPrimitive.getAsString(); - return Long.parseLong(string); - } - throw new OpenemsException("[" + memberName + "] is not a Number: " + jPrimitive); - } - - public static JsonElement getSubElement(JsonElement jElement, String memberName) throws OpenemsException { - JsonObject jObject = getAsJsonObject(jElement); - if (!jObject.has(memberName)) { - throw new OpenemsException("Element [" + memberName + "] is not a Subelement of: " + jElement); - } - return jObject.get(memberName); - } - - /** - * Merges the second Object into the first object - * - * @param j1 - * @param j2 - * @return - */ - public static JsonObject merge(JsonObject j1, JsonObject j2) { - // TODO be smarter: merge down the tree - for (Entry entry : j2.entrySet()) { - j1.add(entry.getKey(), entry.getValue()); - } - return j1; - } - - public static Optional merge(Optional j1Opt, Optional j2Opt) { - if (j1Opt.isPresent() && j2Opt.isPresent()) { - return Optional.of(JsonUtils.merge(j1Opt.get(), j2Opt.get())); - } - if (j1Opt.isPresent()) { - return j1Opt; - } - return j2Opt; - } - - public static boolean hasElement(JsonElement j, String... paths) { - return getMatchingElements(j, paths).size() > 0; - } - - public static Set getMatchingElements(JsonElement j, String... paths) { - Set result = new HashSet(); - if (paths.length == 0) { - // last path element - result.add(j); - return result; - } - String path = paths[0]; - if (j.isJsonObject()) { - JsonObject jO = j.getAsJsonObject(); - if (jO.has(path)) { - List nextPathsList = new ArrayList(Arrays.asList(paths)); - nextPathsList.remove(0); - String[] nextPaths = nextPathsList.toArray(new String[0]); - result.addAll(getMatchingElements(jO.get(path), nextPaths)); - } - } else if (j.isJsonArray()) { - for (JsonElement jE : j.getAsJsonArray()) { - result.addAll(getMatchingElements(jE, paths)); - } - } else if (j.isJsonPrimitive()) { - JsonPrimitive jP = j.getAsJsonPrimitive(); - if (jP.isString()) { - if (jP.getAsString().equals(path)) { - result.add(jP); - } - } - } - return result; - } - - /** - * Pretty print a JsonElement - * - * @param j - */ - public static void prettyPrint(JsonElement j) { - Gson gson = new GsonBuilder().setPrettyPrinting().create(); - String json = gson.toJson(j); - System.out.println(json); - } - - /** - * Parses a string to a JsonElement - * - * @param string - * @return - */ - public static JsonElement parse(String string) throws OpenemsException { - try { - JsonParser parser = new JsonParser(); - return parser.parse(string); - } catch (JsonParseException e) { - throw new OpenemsException("Unable to parse [" + string + "] + to JSON: " + e.getMessage(), e); - } - } - - /* - * Copied from edge - * TODO! - */ - public static JsonElement getAsJsonElement(Object value) throws NotImplementedException { - // null - if (value == null) { - return null; - } - // optional - if (value instanceof Optional) { - if (!((Optional) value).isPresent()) { - return null; - } else { - value = ((Optional) value).get(); - } - } - if (value instanceof Number) { - /* - * Number - */ - return new JsonPrimitive((Number) value); - } else if (value instanceof String) { - /* - * String - */ - return new JsonPrimitive((String) value); - } else if (value instanceof Boolean) { - /* - * Boolean - */ - return new JsonPrimitive((Boolean) value); - } else if (value instanceof Inet4Address) { - /* - * Inet4Address - */ - return new JsonPrimitive(((Inet4Address) value).getHostAddress()); - } else if (value instanceof JsonElement) { - /* - * JsonElement - */ - return (JsonElement) value; - } else if (value instanceof Long[]){ - /* - * Long-Array - */ - JsonArray js = new JsonArray(); - for (Long l : (Long[]) value){ - js.add(new JsonPrimitive((Long) l)); - } - return js; - } - throw new NotImplementedException("Converter for [" + value + "]" + " of type [" // - + value.getClass().getSimpleName() + "]" // - + " to JSON is not implemented."); - } -} +package io.openems.common.utils; + +import java.net.Inet4Address; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonParser; +import com.google.gson.JsonPrimitive; + +import io.openems.common.exceptions.NotImplementedException; +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.types.ChannelEnum; + +// TODO use getAsOptional***() as basis for getAs***() to avoid unnecessary exceptions +public class JsonUtils { + public static JsonArray getAsJsonArray(JsonElement jElement) throws OpenemsException { + if (!jElement.isJsonArray()) { + throw new OpenemsException("This is not a JsonArray: " + jElement); + } + return jElement.getAsJsonArray(); + }; + + public static JsonArray getAsJsonArray(JsonElement jElement, String memberName) throws OpenemsException { + JsonElement jSubElement = getSubElement(jElement, memberName); + if (!jSubElement.isJsonArray()) { + throw new OpenemsException("Element [" + memberName + "] is not a JsonArray: " + jSubElement); + } + return jSubElement.getAsJsonArray(); + }; + + public static Optional getAsOptionalJsonArray(JsonElement jElement, String memberName) { + try { + return Optional.of(getAsJsonArray(jElement, memberName)); + } catch (OpenemsException e) { + return Optional.empty(); + } + } + + public static JsonObject getAsJsonObject(JsonElement jElement) throws OpenemsException { + if (!jElement.isJsonObject()) { + throw new OpenemsException("This is not a JsonObject: " + jElement); + } + return jElement.getAsJsonObject(); + }; + + public static JsonObject getAsJsonObject(JsonElement jElement, String memberName) throws OpenemsException { + JsonElement jsubElement = getSubElement(jElement, memberName); + if (!jsubElement.isJsonObject()) { + throw new OpenemsException("Element [" + memberName + "] is not a JsonObject: " + jsubElement); + } + return jsubElement.getAsJsonObject(); + }; + + public static Optional getAsOptionalJsonObject(JsonElement jElement, String memberName) { + try { + return Optional.of(getAsJsonObject(jElement, memberName)); + } catch (OpenemsException e) { + return Optional.empty(); + } + } + + public static JsonPrimitive getAsPrimitive(JsonElement jElement, String memberName) throws OpenemsException { + JsonElement jSubElement = getSubElement(jElement, memberName); + return getAsPrimitive(jSubElement); + } + + public static JsonPrimitive getAsPrimitive(JsonElement jElement) throws OpenemsException { + if (!jElement.isJsonPrimitive()) { + throw new OpenemsException("This is not a JsonPrimitive: " + jElement); + } + return jElement.getAsJsonPrimitive(); + } + + public static String getAsString(JsonElement jElement) throws OpenemsException { + JsonPrimitive jPrimitive = getAsPrimitive(jElement); + if (!jPrimitive.isString()) { + throw new OpenemsException("This is not a String: " + jPrimitive); + } + return jPrimitive.getAsString(); + } + + public static boolean getAsBoolean(JsonElement jElement) throws OpenemsException { + JsonPrimitive jPrimitive = getAsPrimitive(jElement); + if (!jPrimitive.isBoolean()) { + throw new OpenemsException("This is not a Boolean: " + jPrimitive); + } + return jPrimitive.getAsBoolean(); + } + + public static Optional getAsOptionalString(JsonElement jElement, String memberName) { + try { + return Optional.of(getAsString(jElement, memberName)); + } catch (OpenemsException e) { + return Optional.empty(); + } + } + + public static String getAsString(JsonElement jElement, String memberName) throws OpenemsException { + JsonPrimitive jPrimitive = getAsPrimitive(jElement, memberName); + if (!jPrimitive.isString()) { + throw new OpenemsException("Element [" + memberName + "] is not a String: " + jPrimitive); + } + return jPrimitive.getAsString(); + } + + public static Optional getAsOptionalInt(JsonElement jElement, String memberName) { + try { + return Optional.of(getAsInt(jElement, memberName)); + } catch (OpenemsException e) { + return Optional.empty(); + } + } + + public static Optional getAsOptionalLong(JsonElement jElement, String memberName) { + try { + return Optional.of(getAsLong(jElement, memberName)); + } catch (OpenemsException e) { + return Optional.empty(); + } + } + + public static int getAsInt(JsonElement jElement, String memberName) throws OpenemsException { + JsonPrimitive jPrimitive = getAsPrimitive(jElement, memberName); + if (jPrimitive.isNumber()) { + return jPrimitive.getAsInt(); + } else if (jPrimitive.isString()) { + String string = jPrimitive.getAsString(); + return Integer.parseInt(string); + } + throw new OpenemsException("Element [" + memberName + "] is not an Integer: " + jPrimitive); + } + + public static boolean getAsBoolean(JsonElement jElement, String memberName) throws OpenemsException { + JsonPrimitive jPrimitive = getAsPrimitive(jElement, memberName); + if (!jPrimitive.isBoolean()) { + throw new OpenemsException("Element [" + memberName + "] is not a Boolean: " + jPrimitive); + } + return jPrimitive.getAsBoolean(); + } + + /** + * Takes a json in the form 'YYYY-MM-DD' and converts it to a ZonedDateTime with + * hour, minute and second set to zero. + * + * @param jElement + * @param memberName + * @param timezone + * @return + * @throws OpenemsException + */ + public static ZonedDateTime getAsZonedDateTime(JsonElement jElement, String memberName, ZoneId timezone) + throws OpenemsException { + String[] date = JsonUtils.getAsString(jElement, memberName).split("-"); + try { + int year = Integer.valueOf(date[0]); + int month = Integer.valueOf(date[1]); + int day = Integer.valueOf(date[2]); + return ZonedDateTime.of(year, month, day, 0, 0, 0, 0, timezone); + } catch (ArrayIndexOutOfBoundsException e) { + throw new OpenemsException("Element [" + memberName + "] is not a Date: " + jElement + ". Error: " + e); + } + } + + public static long getAsLong(JsonElement jElement, String memberName) throws OpenemsException { + JsonPrimitive jPrimitive = getAsPrimitive(jElement, memberName); + if (jPrimitive.isNumber()) { + return jPrimitive.getAsLong(); + } else if (jPrimitive.isString()) { + String string = jPrimitive.getAsString(); + return Long.parseLong(string); + } + throw new OpenemsException("[" + memberName + "] is not a Number: " + jPrimitive); + } + + public static JsonElement getSubElement(JsonElement jElement, String memberName) throws OpenemsException { + JsonObject jObject = getAsJsonObject(jElement); + if (!jObject.has(memberName)) { + throw new OpenemsException("Element [" + memberName + "] is not a Subelement of: " + jElement); + } + return jObject.get(memberName); + } + + /** + * Merges the second Object into the first object + * + * @param j1 + * @param j2 + * @return + */ + public static JsonObject merge(JsonObject j1, JsonObject j2) { + // TODO be smarter: merge down the tree + for (Entry entry : j2.entrySet()) { + j1.add(entry.getKey(), entry.getValue()); + } + return j1; + } + + public static Optional merge(Optional j1Opt, Optional j2Opt) { + if (j1Opt.isPresent() && j2Opt.isPresent()) { + return Optional.of(JsonUtils.merge(j1Opt.get(), j2Opt.get())); + } + if (j1Opt.isPresent()) { + return j1Opt; + } + return j2Opt; + } + + public static boolean hasElement(JsonElement j, String... paths) { + return getMatchingElements(j, paths).size() > 0; + } + + public static Set getMatchingElements(JsonElement j, String... paths) { + Set result = new HashSet(); + if (paths.length == 0) { + // last path element + result.add(j); + return result; + } + String path = paths[0]; + if (j.isJsonObject()) { + JsonObject jO = j.getAsJsonObject(); + if (jO.has(path)) { + List nextPathsList = new ArrayList(Arrays.asList(paths)); + nextPathsList.remove(0); + String[] nextPaths = nextPathsList.toArray(new String[0]); + result.addAll(getMatchingElements(jO.get(path), nextPaths)); + } + } else if (j.isJsonArray()) { + for (JsonElement jE : j.getAsJsonArray()) { + result.addAll(getMatchingElements(jE, paths)); + } + } else if (j.isJsonPrimitive()) { + JsonPrimitive jP = j.getAsJsonPrimitive(); + if (jP.isString()) { + if (jP.getAsString().equals(path)) { + result.add(jP); + } + } + } + return result; + } + + /** + * Pretty print a JsonElement + * + * @param j + */ + public static void prettyPrint(JsonElement j) { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + String json = gson.toJson(j); + System.out.println(json); + } + + /** + * Parses a string to a JsonElement + * + * @param string + * @return + */ + public static JsonElement parse(String string) throws OpenemsException { + try { + JsonParser parser = new JsonParser(); + return parser.parse(string); + } catch (JsonParseException e) { + throw new OpenemsException("Unable to parse [" + string + "] + to JSON: " + e.getMessage(), e); + } + } + + /* + * Copied from edge TODO! + */ + public static JsonElement getAsJsonElement(Object value) throws NotImplementedException { + // null + if (value == null) { + return null; + } + // optional + if (value instanceof Optional) { + if (!((Optional) value).isPresent()) { + return null; + } else { + value = ((Optional) value).get(); + } + } + if (value instanceof Number) { + /* + * Number + */ + return new JsonPrimitive((Number) value); + } else if(value instanceof ChannelEnum) { + /* + * ChannelEnum + */ + return new JsonPrimitive(((ChannelEnum)value).getValue()); + } else if (value instanceof String) { + /* + * String + */ + return new JsonPrimitive((String) value); + } else if (value instanceof Boolean) { + /* + * Boolean + */ + return new JsonPrimitive((Boolean) value); + } else if (value instanceof Inet4Address) { + /* + * Inet4Address + */ + return new JsonPrimitive(((Inet4Address) value).getHostAddress()); + } else if (value instanceof JsonElement) { + /* + * JsonElement + */ + return (JsonElement) value; + } else if (value instanceof Long[]){ + /* + * Long-Array + */ + JsonArray js = new JsonArray(); + for (Long l : (Long[]) value){ + js.add(new JsonPrimitive((Long) l)); + } + return js; + } + throw new NotImplementedException("Converter for [" + value + "]" + " of type [" // + + value.getClass().getSimpleName() + "]" // + + " to JSON is not implemented."); + } +} diff --git a/common/src/io/openems/common/websocket/AbstractWebsocketServer.java b/common/src/io/openems/common/websocket/AbstractWebsocketServer.java index 07df2825e0d..b421929b02d 100644 --- a/common/src/io/openems/common/websocket/AbstractWebsocketServer.java +++ b/common/src/io/openems/common/websocket/AbstractWebsocketServer.java @@ -37,7 +37,6 @@ protected abstract void _onMessage(WebSocket websocket, JsonObject jMessage, Opt protected abstract void _onClose(WebSocket websocket, Optional sessionOpt); - @SuppressWarnings("deprecation") public AbstractWebsocketServer(int port, M sessionManager) { super(new InetSocketAddress(port), Lists.newArrayList(new Draft_6455())); this.sessionManager = sessionManager; diff --git a/edge/.classpath b/edge/.classpath index 10569758c03..77874fed6c6 100644 --- a/edge/.classpath +++ b/edge/.classpath @@ -14,17 +14,5 @@ - - - - - - - - - - - - diff --git a/edge/pom.xml b/edge/pom.xml index c45ec706482..70345cc3340 100644 --- a/edge/pom.xml +++ b/edge/pom.xml @@ -5,7 +5,7 @@ http://openems.io io.openems edge - 1.7.1 + 2018.1 jar https://github.com/OpenEMS/openems diff --git a/edge/src/io/openems/api/bridge/Bridge.java b/edge/src/io/openems/api/bridge/Bridge.java index 10b8113108c..1aa668e0009 100644 --- a/edge/src/io/openems/api/bridge/Bridge.java +++ b/edge/src/io/openems/api/bridge/Bridge.java @@ -32,6 +32,7 @@ import io.openems.api.bridge.BridgeEvent.Position; import io.openems.api.channel.DebugChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.scheduler.Scheduler; import io.openems.api.thing.Thing; @@ -55,6 +56,7 @@ public abstract class Bridge extends Thread implements Thing { private DebugChannel requiredCycleTime = new DebugChannel<>("RequiredCycleTime", this); private List eventListener = new ArrayList<>(); private DebugChannel readOtherTaskReadCount = new DebugChannel<>("ReadOtherTaskReadCount", this); + protected ThingStateChannels thingState; /** * Initialize the Thread with a name @@ -64,6 +66,7 @@ public abstract class Bridge extends Thread implements Thing { public Bridge() { log = LoggerFactory.getLogger(this.getClass()); setName(THINGID_PREFIX + instanceCounter++); + thingState = new ThingStateChannels(this); } @Override @@ -127,6 +130,11 @@ public synchronized List getDevices() { return Collections.unmodifiableList(this.devices); } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + public void triggerWrite() { // set the Write-flag isWriteTriggered.set(true); diff --git a/edge/src/io/openems/api/channel/BitToBooleanThingStateChannel.java b/edge/src/io/openems/api/channel/BitToBooleanThingStateChannel.java new file mode 100644 index 00000000000..dc3b640b0f8 --- /dev/null +++ b/edge/src/io/openems/api/channel/BitToBooleanThingStateChannel.java @@ -0,0 +1,31 @@ +package io.openems.api.channel; + +import java.util.Optional; + +import io.openems.api.channel.thingstate.ThingStateEnum; +import io.openems.api.thing.Thing; + +public class BitToBooleanThingStateChannel extends ThingStateChannel implements ChannelChangeListener{ + + private ReadChannel valueChannel; + private int bitIndex; + + public BitToBooleanThingStateChannel(ThingStateEnum state, Thing parent, ReadChannel channel, int bitIndex){ + super(state, parent); + this.valueChannel = channel; + this.valueChannel.addChangeListener(this); + this.bitIndex = bitIndex; + } + + @Override + public void channelChanged(Channel channel, Optional newValue, Optional oldValue) { + if(valueChannel.isValuePresent()) { + if(valueChannel.getValue().longValue() << ~bitIndex < 0) { + updateValue(true); + }else { + updateValue(false); + } + } + } + +} diff --git a/edge/src/io/openems/api/channel/ReadChannel.java b/edge/src/io/openems/api/channel/ReadChannel.java index 047c82686aa..b9bf6cb07b2 100644 --- a/edge/src/io/openems/api/channel/ReadChannel.java +++ b/edge/src/io/openems/api/channel/ReadChannel.java @@ -182,6 +182,14 @@ public Optional valueOptional() { return value; }; + public boolean isValuePresent() { + return value.isPresent(); + } + + public T getValue() { + return value.get(); + } + public String unitOptional() { return unit; } diff --git a/edge/src/io/openems/api/channel/StaticThingStateChannel.java b/edge/src/io/openems/api/channel/StaticThingStateChannel.java new file mode 100644 index 00000000000..341b8b04138 --- /dev/null +++ b/edge/src/io/openems/api/channel/StaticThingStateChannel.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.api.channel; + +import io.openems.api.channel.thingstate.ThingStateEnum; +import io.openems.api.thing.Thing; + +public class StaticThingStateChannel extends ThingStateChannel { + + public StaticThingStateChannel(ThingStateEnum state, Thing parent, boolean value) { + super(state, parent); + this.updateValue(value); + } + + @Override public StaticThingStateChannel addUpdateListener(ChannelUpdateListener... listeners) { + super.addUpdateListener(listeners); + return this; + } + + @Override public StaticThingStateChannel addChangeListener(ChannelChangeListener... listeners) { + super.addChangeListener(listeners); + return this; + } + + public void setValue(boolean b) { + this.updateValue(b); + } + +} diff --git a/edge/src/io/openems/api/channel/StaticValueChannel.java b/edge/src/io/openems/api/channel/StaticValueChannel.java index 2358e07844d..b4273699397 100644 --- a/edge/src/io/openems/api/channel/StaticValueChannel.java +++ b/edge/src/io/openems/api/channel/StaticValueChannel.java @@ -1,71 +1,75 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.api.channel; - -import io.openems.api.thing.Thing; - -public class StaticValueChannel extends ReadChannel { - - public StaticValueChannel(String id, Thing parent, T value) { - super(id, parent); - this.updateValue(value); - } - - @Override public StaticValueChannel unit(String unit) { - super.unit(unit); - return this; - } - - @Override public StaticValueChannel multiplier(Long multiplier) { - super.multiplier(multiplier); - return this; - } - - @Override public StaticValueChannel delta(Long delta) { - super.delta(delta); - return this; - } - - @Override public StaticValueChannel required() { - return this; - } - - @Override public StaticValueChannel interval(T min, T max) { - super.interval(min, max); - return this; - } - - @Override public StaticValueChannel addUpdateListener(ChannelUpdateListener... listeners) { - super.addUpdateListener(listeners); - return this; - } - - @Override public StaticValueChannel addChangeListener(ChannelChangeListener... listeners) { - super.addChangeListener(listeners); - return this; - } - - @Override public StaticValueChannel label(T value, String label) { - super.label(value, label); - return this; - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.api.channel; + +import io.openems.api.thing.Thing; + +public class StaticValueChannel extends ReadChannel { + + public StaticValueChannel(String id, Thing parent, T value) { + super(id, parent); + this.updateValue(value); + } + + @Override public StaticValueChannel unit(String unit) { + super.unit(unit); + return this; + } + + @Override public StaticValueChannel multiplier(Long multiplier) { + super.multiplier(multiplier); + return this; + } + + @Override public StaticValueChannel delta(Long delta) { + super.delta(delta); + return this; + } + + @Override public StaticValueChannel required() { + return this; + } + + @Override public StaticValueChannel interval(T min, T max) { + super.interval(min, max); + return this; + } + + @Override public StaticValueChannel addUpdateListener(ChannelUpdateListener... listeners) { + super.addUpdateListener(listeners); + return this; + } + + @Override public StaticValueChannel addChangeListener(ChannelChangeListener... listeners) { + super.addChangeListener(listeners); + return this; + } + + @Override public StaticValueChannel label(T value, String label) { + super.label(value, label); + return this; + } + + public void setValue(T b) { + this.updateValue(b); + } + +} diff --git a/edge/src/io/openems/api/channel/StatusBitChannels.java b/edge/src/io/openems/api/channel/StatusBitChannels.java index 21e5b4f0e7e..bdbe790d4eb 100644 --- a/edge/src/io/openems/api/channel/StatusBitChannels.java +++ b/edge/src/io/openems/api/channel/StatusBitChannels.java @@ -1,71 +1,71 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.api.channel; - -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; -import java.util.StringJoiner; - -import io.openems.api.thing.Thing; - -public class StatusBitChannels extends ReadChannel { - private final Set channels = new HashSet<>(); - - public StatusBitChannels(String id, Thing parent) { - super(id, parent); - } - - public StatusBitChannel channel(StatusBitChannel channel) { - this.channels.add(channel); - return channel; - } - - public Set labels() { - Set result = new HashSet<>(); - for (StatusBitChannel channel : channels) { - result.addAll(channel.labels()); - } - return result; - } - - @Override public Optional labelOptional() { - Set labels = this.labels(); - if (labels.isEmpty()) { - return Optional.empty(); - } else { - StringJoiner joiner = new StringJoiner(","); - for (String label : labels) { - joiner.add(label); - } - return Optional.of(joiner.toString()); - } - }; - - @Override public String toString() { - Optional string = labelOptional(); - if (string.isPresent()) { - return string.get(); - } else { - return ""; - } - } -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.api.channel; + +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.StringJoiner; + +import io.openems.api.thing.Thing; + +public class StatusBitChannels extends ReadChannel { + private final Set channels = new HashSet<>(); + + public StatusBitChannels(String id, Thing parent) { + super(id, parent); + } + + public StatusBitChannel channel(StatusBitChannel channel) { + this.channels.add(channel); + return channel; + } + + public Set labels() { + Set result = new HashSet<>(); + for (StatusBitChannel channel : channels) { + result.addAll(channel.labels()); + } + return result; + } + + @Override public Optional labelOptional() { + Set labels = this.labels(); + if (labels.isEmpty()) { + return Optional.empty(); + } else { + StringJoiner joiner = new StringJoiner(","); + for (String label : labels) { + joiner.add(label); + } + return Optional.of(joiner.toString()); + } + }; + + @Override public String toString() { + Optional string = labelOptional(); + if (string.isPresent()) { + return string.get(); + } else { + return ""; + } + } +} diff --git a/edge/src/io/openems/api/channel/ThingStateChannel.java b/edge/src/io/openems/api/channel/ThingStateChannel.java new file mode 100644 index 00000000000..5584efde9ea --- /dev/null +++ b/edge/src/io/openems/api/channel/ThingStateChannel.java @@ -0,0 +1,18 @@ +package io.openems.api.channel; + +import io.openems.api.channel.thingstate.ThingStateEnum; +import io.openems.api.thing.Thing; + +public class ThingStateChannel extends ReadChannel { + + private final ThingStateEnum state; + + public ThingStateChannel(ThingStateEnum state, Thing parent) { + super(state.getChannelId(), parent); + this.state = state; + } + + public String name() { + return this.state.toString(); + } +} diff --git a/edge/src/io/openems/api/channel/ValueToBooleanThingStateChannel.java b/edge/src/io/openems/api/channel/ValueToBooleanThingStateChannel.java new file mode 100644 index 00000000000..338fc7a9073 --- /dev/null +++ b/edge/src/io/openems/api/channel/ValueToBooleanThingStateChannel.java @@ -0,0 +1,31 @@ +package io.openems.api.channel; + +import java.util.Optional; + +import io.openems.api.channel.thingstate.ThingStateEnum; +import io.openems.api.thing.Thing; + +public class ValueToBooleanThingStateChannel extends ThingStateChannel implements ChannelChangeListener{ + + private ReadChannel valueChannel; + private long value; + + public ValueToBooleanThingStateChannel(ThingStateEnum state, Thing parent, ReadChannel channel, long value) { + super(state, parent); + this.valueChannel = channel; + this.valueChannel.addChangeListener(this); + this.value = value; + } + + @Override + public void channelChanged(Channel channel, Optional newValue, Optional oldValue) { + if(valueChannel.isValuePresent()) { + if(valueChannel.getValue().longValue() == value) { + updateValue(true); + }else { + updateValue(false); + } + } + } + +} diff --git a/edge/src/io/openems/api/channel/thingstate/FaultEnum.java b/edge/src/io/openems/api/channel/thingstate/FaultEnum.java new file mode 100644 index 00000000000..47d0155d0e3 --- /dev/null +++ b/edge/src/io/openems/api/channel/thingstate/FaultEnum.java @@ -0,0 +1,10 @@ +package io.openems.api.channel.thingstate; + +public interface FaultEnum extends ThingStateEnum { + + @Override + default String getChannelId() { + return "Fault/" + this.getValue(); + } + +} diff --git a/edge/src/io/openems/api/channel/thingstate/ThingState.java b/edge/src/io/openems/api/channel/thingstate/ThingState.java new file mode 100644 index 00000000000..b76ab28ddf6 --- /dev/null +++ b/edge/src/io/openems/api/channel/thingstate/ThingState.java @@ -0,0 +1,60 @@ +package io.openems.api.channel.thingstate; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import io.openems.common.types.ChannelEnum; + +public enum ThingState implements ChannelEnum { + RUN(0), WARNING(1), FAULT(2); + + private static Map resources = new HashMap<>(); + + private int value; + + private ThingState(int value) { + this.value = value; + } + + @Override + public int getValue() { + return this.value; + } + + @Override + public String getName(Locale locale) { + ResourceBundle resource = getResource(locale); + if(resource != null) { + try { + return resource.getString(name()); + }catch(MissingResourceException e) { + // no handling needed + } + } + return name(); + } + + private static ResourceBundle getResource(Locale locale) { + ResourceBundle resource = resources.get(locale); + if (resource != null) { + return resource; + } else { + try { + resource = ResourceBundle.getBundle("ThingStateNames", locale); + resources.put(locale, resource); + return resource; + } catch (MissingResourceException e) { + try { + resource = ResourceBundle.getBundle("ThingStateNames"); + resources.put(locale, resource); + return resource; + } catch (MissingResourceException ex) { + return null; + } + } + } + } +} diff --git a/edge/src/io/openems/api/channel/thingstate/ThingStateChannels.java b/edge/src/io/openems/api/channel/thingstate/ThingStateChannels.java new file mode 100644 index 00000000000..058764d5082 --- /dev/null +++ b/edge/src/io/openems/api/channel/thingstate/ThingStateChannels.java @@ -0,0 +1,133 @@ +package io.openems.api.channel.thingstate; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import io.openems.api.channel.Channel; +import io.openems.api.channel.ChannelChangeListener; +import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.ThingStateChannel; +import io.openems.api.exception.ConfigException; +import io.openems.api.thing.Thing; + +public class ThingStateChannels extends ReadChannel implements ChannelChangeListener { + + private List warningChannels; + private List faultChannels; + private List childChannels; + private Set channelNames; + + public ThingStateChannels(Thing parent){ + super("State", parent); + this.warningChannels = new ArrayList<>(); + this.faultChannels = new ArrayList<>(); + this.channelNames = new HashSet<>(); + this.childChannels = new ArrayList<>(); + updateState(); + } + + public void addWarningChannel(ThingStateChannel channel) throws ConfigException { + if (!this.channelNames.contains(channel.address())) { + this.warningChannels.add(channel); + this.channelNames.add(channel.address()); + channel.addChangeListener(this); + updateState(); + } else { + throw new ConfigException("A channel with the name [" + channel.address() + "] is already registered!"); + } + } + + public void removeWarningChannel(ThingStateChannel channel) { + channel.removeChangeListener(this); + this.channelNames.remove(channel.address()); + this.warningChannels.remove(channel); + updateState(); + } + + public void addFaultChannel(ThingStateChannel channel) throws ConfigException { + if (!this.channelNames.contains(channel.address())) { + this.faultChannels.add(channel); + this.channelNames.add(channel.address()); + channel.addChangeListener(this); + updateState(); + } else { + throw new ConfigException("A channel with the name [" + channel.address() + "] is already registered!"); + } + } + + public void removeFaultChannel(ThingStateChannel channel) { + channel.removeChangeListener(this); + this.channelNames.remove(channel.address()); + this.faultChannels.remove(channel); + updateState(); + } + + public List getWarningChannels() { + List warningChannels = new ArrayList<>(); + warningChannels.addAll(this.warningChannels); + for(ThingStateChannels child : this.childChannels) { + warningChannels.addAll(child.getWarningChannels()); + } + return warningChannels; + } + + public List getFaultChannels() { + List faultChannels = new ArrayList<>(); + faultChannels.addAll(this.faultChannels); + for(ThingStateChannels child : this.childChannels) { + faultChannels.addAll(child.getFaultChannels()); + } + return this.faultChannels; + } + + public void addChildChannel(ThingStateChannels child) { + this.childChannels.add(child); + child.addChangeListener(this); + updateState(); + } + + public void removeChildChannel(ThingStateChannels child) { + child.removeChangeListener(this); + this.childChannels.add(child); + updateState(); + } + + @Override + public void channelChanged(Channel channel, Optional newValue, Optional oldValue) { + updateState(); + } + + private void updateState() { + for(ThingStateChannels child : this.childChannels) { + if(child.isValuePresent()) { + switch(child.getValue()) { + case FAULT: + updateValue(ThingState.FAULT); + return; + case WARNING: + updateValue(ThingState.WARNING); + return; + default: + break; + } + } + } + for (ThingStateChannel faultChannel : faultChannels) { + if (faultChannel.isValuePresent() && faultChannel.getValue()) { + updateValue(ThingState.FAULT); + return; + } + } + for (ThingStateChannel warningChannel : warningChannels) { + if (warningChannel.isValuePresent() && warningChannel.getValue()) { + updateValue(ThingState.WARNING); + return; + } + } + updateValue(ThingState.RUN); + } + +} diff --git a/edge/src/io/openems/api/channel/thingstate/ThingStateEnum.java b/edge/src/io/openems/api/channel/thingstate/ThingStateEnum.java new file mode 100644 index 00000000000..0fdf8f6a7b1 --- /dev/null +++ b/edge/src/io/openems/api/channel/thingstate/ThingStateEnum.java @@ -0,0 +1,9 @@ +package io.openems.api.channel.thingstate; + +public interface ThingStateEnum { + + int getValue(); + + String getChannelId(); + +} diff --git a/edge/src/io/openems/api/channel/thingstate/WarningEnum.java b/edge/src/io/openems/api/channel/thingstate/WarningEnum.java new file mode 100644 index 00000000000..f297152412e --- /dev/null +++ b/edge/src/io/openems/api/channel/thingstate/WarningEnum.java @@ -0,0 +1,10 @@ +package io.openems.api.channel.thingstate; + +public interface WarningEnum extends ThingStateEnum { + + @Override + default String getChannelId() { + return "Warning/" + this.getValue(); + } + +} diff --git a/edge/src/io/openems/api/device/Device.java b/edge/src/io/openems/api/device/Device.java index 5202cf3b045..55a586d2ed6 100644 --- a/edge/src/io/openems/api/device/Device.java +++ b/edge/src/io/openems/api/device/Device.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.Set; import org.slf4j.Logger; @@ -30,21 +31,27 @@ import io.openems.api.bridge.Bridge; import io.openems.api.bridge.BridgeReadTask; import io.openems.api.bridge.BridgeWriteTask; +import io.openems.api.channel.Channel; +import io.openems.api.channel.ChannelChangeListener; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.nature.DeviceNature; import io.openems.api.exception.OpenemsException; import io.openems.api.thing.Thing; -public abstract class Device implements Thing { +public abstract class Device implements Thing, ChannelChangeListener { public final static String THINGID_PREFIX = "_device"; private static int instanceCounter = 0; protected final Logger log; private Bridge bridge = null; private final String thingId; + private ThingStateChannels thingState; public Device(Bridge parent) throws OpenemsException { this.thingId = THINGID_PREFIX + instanceCounter++; log = LoggerFactory.getLogger(this.getClass()); this.bridge = parent; + this.thingState = new ThingStateChannels(this); + this.thingState.addChildChannel(this.bridge.getStateChannel()); } public Bridge getBridge() { @@ -98,4 +105,23 @@ public List getWriteTasks() { } return writeTasks; } + + @Override + public void channelChanged(Channel channel, Optional newValue, Optional oldValue) { + if (oldValue.isPresent()) { + if (oldValue.get() instanceof DeviceNature) { + this.thingState.removeChildChannel(((DeviceNature) oldValue.get()).getStateChannel()); + } + } + if (newValue.isPresent()) { + if (newValue.get() instanceof DeviceNature) { + this.thingState.addChildChannel(((DeviceNature) newValue.get()).getStateChannel()); + } + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } } diff --git a/edge/src/io/openems/api/device/nature/ess/EssNature.java b/edge/src/io/openems/api/device/nature/ess/EssNature.java index b735451c74f..f99f0b50d51 100644 --- a/edge/src/io/openems/api/device/nature/ess/EssNature.java +++ b/edge/src/io/openems/api/device/nature/ess/EssNature.java @@ -1,88 +1,85 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.api.device.nature.ess; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.channel.ReadChannel; -import io.openems.api.channel.StatusBitChannels; -import io.openems.api.channel.WriteChannel; -import io.openems.api.device.nature.DeviceNature; -import io.openems.api.doc.ChannelInfo; - -public interface EssNature extends DeviceNature { - /* - * Constants - */ - public final int DEFAULT_MINSOC = 10; - - public final String OFF = "Off"; - public final String ON = "On"; - - public final String OFF_GRID = "Off-Grid"; - public final String ON_GRID = "On-Grid"; - - public final String STANDBY = "Standby"; - public final String START = "Start"; - public final String STOP = "Stop"; - public final String FAULT = "Fault"; - - /* - * Config - */ - @ChannelInfo(title = "Min-SOC", description = "Sets the minimal SOC.", type = Integer.class) - public ConfigChannel minSoc(); - - @ChannelInfo(title = "Charge-SOC", description = "Sets the force charge SOC.", type = Integer.class, isOptional = true) - public ConfigChannel chargeSoc(); - - /* - * Read Channels - */ - public ReadChannel gridMode(); - - @ChannelInfo(type = Long.class) - public ReadChannel soc(); - - @ChannelInfo(type = Long.class) - public ReadChannel systemState(); - - @ChannelInfo(type = Long.class) - public ReadChannel allowedCharge(); - - @ChannelInfo(type = Long.class) - public ReadChannel allowedDischarge(); - - @ChannelInfo(type = Long.class) - public ReadChannel allowedApparent(); - - @ChannelInfo(type = Long.class) - public ReadChannel capacity(); - - @ChannelInfo(type = Long.class) - public ReadChannel maxNominalPower(); - - public StatusBitChannels warning(); - - /* - * Write Channels - */ - public WriteChannel setWorkState(); -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.api.device.nature.ess; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.WriteChannel; +import io.openems.api.device.nature.DeviceNature; +import io.openems.api.doc.ChannelInfo; + +public interface EssNature extends DeviceNature { + /* + * Constants + */ + public final int DEFAULT_MINSOC = 10; + + public final String OFF = "Off"; + public final String ON = "On"; + + public final String OFF_GRID = "Off-Grid"; + public final String ON_GRID = "On-Grid"; + + public final String STANDBY = "Standby"; + public final String START = "Start"; + public final String STOP = "Stop"; + public final String FAULT = "Fault"; + + /* + * Config + */ + @ChannelInfo(title = "Min-SOC", description = "Sets the minimal SOC.", type = Integer.class) + public ConfigChannel minSoc(); + + @ChannelInfo(title = "Charge-SOC", description = "Sets the force charge SOC.", type = Integer.class, isOptional = true) + public ConfigChannel chargeSoc(); + + /* + * Read Channels + */ + public ReadChannel gridMode(); + + @ChannelInfo(type = Long.class) + public ReadChannel soc(); + + @ChannelInfo(type = Long.class) + public ReadChannel systemState(); + + @ChannelInfo(type = Long.class) + public ReadChannel allowedCharge(); + + @ChannelInfo(type = Long.class) + public ReadChannel allowedDischarge(); + + @ChannelInfo(type = Long.class) + public ReadChannel allowedApparent(); + + @ChannelInfo(type = Long.class) + public ReadChannel capacity(); + + @ChannelInfo(type = Long.class) + public ReadChannel maxNominalPower(); + + /* + * Write Channels + */ + public WriteChannel setWorkState(); +} diff --git a/edge/src/io/openems/api/thing/Thing.java b/edge/src/io/openems/api/thing/Thing.java index 473468da5b1..8e06b542e9e 100644 --- a/edge/src/io/openems/api/thing/Thing.java +++ b/edge/src/io/openems/api/thing/Thing.java @@ -20,6 +20,11 @@ *******************************************************************************/ package io.openems.api.thing; +import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.thingstate.ThingState; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.doc.ChannelInfo; + public interface Thing { public String id(); @@ -40,6 +45,21 @@ public default void init() { } + @ChannelInfo(type = ThingState.class) + public ThingStateChannels getStateChannel(); + + @SuppressWarnings("unchecked") + public default ReadChannel[] getFaultChannels(){ + ThingStateChannels stateChannel = getStateChannel(); + return stateChannel.getFaultChannels().toArray(new ReadChannel[stateChannel.getFaultChannels().size()]); + } + + @SuppressWarnings("unchecked") + public default ReadChannel[] getWarningChannels(){ + ThingStateChannels stateChannel = getStateChannel(); + return stateChannel.getWarningChannels().toArray(new ReadChannel[stateChannel.getWarningChannels().size()]); + } + /** * Sets the Thing annotation. This method is called after the thing was initialized via init() * diff --git a/edge/src/io/openems/api/translation/ChannelTranslation.java b/edge/src/io/openems/api/translation/ChannelTranslation.java new file mode 100644 index 00000000000..848d87ddc83 --- /dev/null +++ b/edge/src/io/openems/api/translation/ChannelTranslation.java @@ -0,0 +1,63 @@ +package io.openems.api.translation; + +import java.util.HashMap; +import java.util.Locale; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +public class ChannelTranslation { + + private final String channelId; + private final HashMap channelNameTranslations; + private final HashMap channelDescriptionTranslations; + + public ChannelTranslation(String channelId,String defaultChannelName, String defaultChannelDescription) throws TranslationException { + this.channelId = channelId; + this.channelNameTranslations = new HashMap<>(); + this.channelDescriptionTranslations = new HashMap<>(); + setChannelNameTranslation(Locale.ENGLISH, defaultChannelName); + setChannelDescriptionTranslation(Locale.ENGLISH, defaultChannelDescription); + } + + public String getId() { + return this.channelId; + } + + public void setChannelNameTranslation(Locale locale, String translation) throws TranslationException { + if (locale != null && translation != null && translation.length() > 0) { + this.channelNameTranslations.put(locale, translation); + } else { + throw new TranslationException("The Locale or translation is Empty!"); + } + } + + public void setChannelDescriptionTranslation(Locale locale, String translation) throws TranslationException { + if (locale != null && translation != null && translation.length() > 0) { + this.channelDescriptionTranslations.put(locale, translation); + } else { + throw new TranslationException("The Locale or translation is Empty!"); + } + } + + public String getChannelName(Locale locale) { + if(this.channelNameTranslations.containsKey(locale)) { + return this.channelNameTranslations.get(locale); + } + return this.channelNameTranslations.get(Locale.ENGLISH); + } + + public String getChannelDescription(Locale locale) { + if(this.channelDescriptionTranslations.containsKey(locale)) { + return this.channelDescriptionTranslations.get(locale); + } + return this.channelDescriptionTranslations.get(Locale.ENGLISH); + } + + public JsonElement getAsJson(Locale locale) { + JsonObject translation = new JsonObject(); + translation.addProperty("name", this.channelNameTranslations.get(locale)); + translation.addProperty("description", this.channelDescriptionTranslations.get(locale)); + return translation; + } +} diff --git a/edge/src/io/openems/api/translation/ControllerTranslation.java b/edge/src/io/openems/api/translation/ControllerTranslation.java new file mode 100644 index 00000000000..08fc0d88a4b --- /dev/null +++ b/edge/src/io/openems/api/translation/ControllerTranslation.java @@ -0,0 +1,10 @@ +package io.openems.api.translation; + +public class ControllerTranslation extends ThingTranslation{ + + public ControllerTranslation(Class thingClass, String defaultThingName, String defaultThingDescription) + throws TranslationException { + super(thingClass, defaultThingName, defaultThingDescription); + } + +} diff --git a/edge/src/io/openems/api/translation/DeviceTranslation.java b/edge/src/io/openems/api/translation/DeviceTranslation.java new file mode 100644 index 00000000000..1119a386cff --- /dev/null +++ b/edge/src/io/openems/api/translation/DeviceTranslation.java @@ -0,0 +1,11 @@ +package io.openems.api.translation; + +public class DeviceTranslation extends ThingTranslation{ + + public DeviceTranslation(Class thingClass, String defaultThingName, String defaultThingDescription) + throws TranslationException { + super(thingClass, defaultThingName, defaultThingDescription); + } + + +} diff --git a/edge/src/io/openems/api/translation/ThingTranslation.java b/edge/src/io/openems/api/translation/ThingTranslation.java new file mode 100644 index 00000000000..a4d11aaaac5 --- /dev/null +++ b/edge/src/io/openems/api/translation/ThingTranslation.java @@ -0,0 +1,91 @@ +package io.openems.api.translation; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +public abstract class ThingTranslation { + + private final Class thingClass; + private final HashMap channels; + private final HashMap thingNameTranslations; + private final HashMap thingDescriptionTranslations; + + public ThingTranslation(Class thingClass, String defaultThingName, String defaultThingDescription) throws TranslationException { + this.thingClass = thingClass; + this.channels = new HashMap<>(); + this.thingNameTranslations = new HashMap<>(); + this.thingDescriptionTranslations = new HashMap<>(); + this.setNameTranslation(Locale.ENGLISH, defaultThingName); + this.setDescriptionTranslation(Locale.ENGLISH, defaultThingDescription); + } + + public Class getThingClass() { + return this.thingClass; + } + + public void addChannelTranslation(ChannelTranslation translation) throws TranslationException { + if (translation != null && translation.getId() != null) { + if (this.channels.containsKey(translation.getId())) { + throw new TranslationException("The ChannelTranslation for "+translation.getId()+" is already existing!"); + } else { + this.channels.put(translation.getId(), translation); + } + } else { + throw new TranslationException("The channeltranslation is null!"); + } + } + /** + * Get the Channel Translatin by the ChannelId. + * @param channelId + * @return the Translation object or null. + */ + public ChannelTranslation getChannelTranslation(String channelId) { + return this.channels.get(channelId); + } + + public void setNameTranslation(Locale locale, String translation) throws TranslationException { + if (locale != null && translation != null && translation.length() > 0) { + this.thingNameTranslations.put(locale, translation); + } else { + throw new TranslationException("The Locale or translation is Empty!"); + } + } + + public void setDescriptionTranslation(Locale locale, String translation) throws TranslationException { + if (locale != null && translation != null && translation.length() > 0) { + this.thingDescriptionTranslations.put(locale, translation); + } else { + throw new TranslationException("The Locale or translation is Empty!"); + } + } + + public String getName(Locale locale) { + if(this.thingNameTranslations.containsKey(locale)) { + return this.thingNameTranslations.get(locale); + } + return this.thingNameTranslations.get(Locale.ENGLISH); + } + + public String getDescription(Locale locale) { + if(this.thingDescriptionTranslations.containsKey(locale)) { + return this.thingDescriptionTranslations.get(locale); + } + return this.thingDescriptionTranslations.get(Locale.ENGLISH); + } + + public JsonElement getAsJson(Locale locale) { + JsonObject translation = new JsonObject(); + translation.addProperty("name", this.thingNameTranslations.get(locale)); + translation.addProperty("description", this.thingDescriptionTranslations.get(locale)); + JsonObject channelTranslations = new JsonObject(); + for(Map.Entry channelTranslation: this.channels.entrySet()) { + channelTranslations.add(channelTranslation.getKey(), channelTranslation.getValue().getAsJson(locale)); + } + translation.add("channels", channelTranslations); + return translation; + } +} diff --git a/edge/src/io/openems/api/translation/TranslationException.java b/edge/src/io/openems/api/translation/TranslationException.java new file mode 100644 index 00000000000..06825f431df --- /dev/null +++ b/edge/src/io/openems/api/translation/TranslationException.java @@ -0,0 +1,32 @@ +package io.openems.api.translation; + +public class TranslationException extends RuntimeException { + + /** + * + */ + private static final long serialVersionUID = -189217968357389677L; + + public TranslationException() { + super(); + } + + public TranslationException(String arg0, Throwable arg1, boolean arg2, boolean arg3) { + super(arg0, arg1, arg2, arg3); + } + + public TranslationException(String arg0, Throwable arg1) { + super(arg0, arg1); + } + + public TranslationException(String arg0) { + super(arg0); + } + + public TranslationException(Throwable arg0) { + super(arg0); + } + + + +} diff --git a/edge/src/io/openems/api/translation/Translator.java b/edge/src/io/openems/api/translation/Translator.java new file mode 100644 index 00000000000..31a6104ec64 --- /dev/null +++ b/edge/src/io/openems/api/translation/Translator.java @@ -0,0 +1,49 @@ +package io.openems.api.translation; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +import com.google.gson.JsonObject; + +public class Translator { + + private static Translator instance; + private Map, ThingTranslation> thingTranslations; + + private Translator() { + this.thingTranslations = new HashMap<>(); + } + + public static Translator getInstance() { + if(instance == null) { + instance = new Translator(); + } + return instance; + } + + public void addThingTranslation(ThingTranslation translation) throws TranslationException { + if (translation != null && translation.getThingClass() != null) { + if (this.thingTranslations.containsKey(translation.getThingClass())) { + throw new TranslationException("The ThingTranslation for "+translation.getThingClass()+" is already existing!"); + } else { + this.thingTranslations.put(translation.getThingClass(), translation); + } + } else { + throw new TranslationException("The thingtranslation is null!"); + } + } + + public ThingTranslation getThingTranslation(Class thingClass) { + return this.thingTranslations.get(thingClass); + } + + public JsonObject getAsJson(Locale locale) { + JsonObject translation = new JsonObject(); + for(Map.Entry, ThingTranslation> thingTranslation:thingTranslations.entrySet()) { + translation.add(thingTranslation.getKey().getName(), thingTranslation.getValue().getAsJson(locale)); + } + return translation; + } + +} diff --git a/edge/src/io/openems/core/ThingRepository.java b/edge/src/io/openems/core/ThingRepository.java index ad348f8b243..aa743e4de0d 100644 --- a/edge/src/io/openems/core/ThingRepository.java +++ b/edge/src/io/openems/core/ThingRepository.java @@ -31,6 +31,7 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.Optional; import java.util.Set; @@ -155,35 +156,43 @@ public synchronized void addThing(Thing thing) { // Add Channels thingConfigChannels ThingDoc thingDoc = classRepository.getThingDoc(thing.getClass()); - for (ChannelDoc channelDoc : thingDoc.getConfigChannelDocs()) { + for (ChannelDoc channelDoc : thingDoc.getChannelDocs()) { Member member = channelDoc.getMember(); try { List channels = new ArrayList<>(); + java.util.function.Consumer addToChannels = (c) -> { + if(c == null) { + log.error( + "Channel is returning null! Thing [" + thing.id() + "], Member [" + member.getName() + "]"); + } else { + channels.add(c); + } + }; if (member instanceof Method) { if (((Method) member).getReturnType().isArray()) { Channel[] ch = (Channel[]) ((Method) member).invoke(thing); for (Channel c : ch) { - channels.add(c); + addToChannels.accept(c); } } else { // It's a Method with ReturnType Channel - channels.add((Channel) ((Method) member).invoke(thing)); + Channel c = (Channel) ((Method) member).invoke(thing); + addToChannels.accept(c); } } else if (member instanceof Field) { // It's a Field with Type Channel - channels.add((Channel) ((Field) member).get(thing)); + Channel c = (Channel) ((Field) member).get(thing); + addToChannels.accept(c); } else { continue; } if (channels.isEmpty()) { - log.error( - "Channel is returning null! Thing [" + thing.id() + "], Member [" + member.getName() + "]"); continue; } for (Channel channel : channels) { + // Add Channel to thingChannels + thingChannels.put(thing, channel.id(), channel); if (channel instanceof ConfigChannel) { - // Add Channel to thingChannels - thingChannels.put(thing, channel.id(), channel); // Add Channel to configChannels thingConfigChannels.put(thing, (ConfigChannel) channel); @@ -408,7 +417,8 @@ public Optional getChannel(String thingId, String channelId) { if (thing == null) { return Optional.empty(); } - Channel channel = thingChannels.row(thing).get(channelId); + Map channels = thingChannels.row(thing); + Channel channel = channels.get(channelId); return Optional.ofNullable(channel); } diff --git a/edge/src/io/openems/core/utilities/BitUtils.java b/edge/src/io/openems/core/utilities/BitUtils.java index d75b521ad63..ac662f1eba2 100644 --- a/edge/src/io/openems/core/utilities/BitUtils.java +++ b/edge/src/io/openems/core/utilities/BitUtils.java @@ -20,6 +20,7 @@ public static int getBitLength(Class type) throws NotImplementedException { case SHORT: return BYTES_SHORT * BITS; + case ENUM: case INTEGER: return BYTES_INT * BITS; @@ -64,8 +65,11 @@ public static byte[] toBytes(Object value) throws NotImplementedException { case JSON_OBJECT: case DEVICE_NATURE: case THING_MAP: + case ENUM: // igore - no error return new byte[0]; + default: + break; } throw new NotImplementedException( "Converter to Byte for value [" + value + "] of type [" + type + "] is not implemented."); @@ -97,8 +101,11 @@ public static Object toObject(Class type, byte... value) throws NotImplemente case JSON_OBJECT: case DEVICE_NATURE: case THING_MAP: + case ENUM: throw new NotImplementedException( "Converter to Byte for value [" + value + "] of type [" + type + "] is not implemented."); + default: + break; } throw new NotImplementedException( "Converter to Byte for value [" + value + "] of type [" + type + "] is not implemented."); diff --git a/edge/src/io/openems/core/utilities/OpenemsTypes.java b/edge/src/io/openems/core/utilities/OpenemsTypes.java index 6b916ab4da3..eea06aa8ab2 100644 --- a/edge/src/io/openems/core/utilities/OpenemsTypes.java +++ b/edge/src/io/openems/core/utilities/OpenemsTypes.java @@ -8,6 +8,7 @@ import io.openems.api.controller.ThingMap; import io.openems.api.device.nature.DeviceNature; import io.openems.api.exception.NotImplementedException; +import io.openems.common.types.ChannelEnum; /** * All types that are used somewhere in the system. This helps with type casting and reflection in certain classes, as @@ -36,7 +37,12 @@ public enum OpenemsTypes { /* * Things */ - DEVICE_NATURE, THING_MAP; + DEVICE_NATURE, THING_MAP, + /* + * Enum + */ + ENUM + ; public static OpenemsTypes get(Class type) throws NotImplementedException { if (Short.class.isAssignableFrom(type)) { @@ -74,6 +80,8 @@ public static OpenemsTypes get(Class type) throws NotImplementedException { } else if (ThingMap.class.isAssignableFrom(type)) { return THING_MAP; + }else if (ChannelEnum.class.isAssignableFrom(type)) { + return ENUM; } throw new NotImplementedException("Type [" + type + "] is not defined as OpenemsType."); } diff --git a/edge/src/io/openems/impl/controller/acisland/AcIsland.java b/edge/src/io/openems/impl/controller/acisland/AcIsland.java index efaf1fb9152..3031cbcc9e9 100644 --- a/edge/src/io/openems/impl/controller/acisland/AcIsland.java +++ b/edge/src/io/openems/impl/controller/acisland/AcIsland.java @@ -25,6 +25,7 @@ import io.openems.api.channel.Channel; import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.device.nature.ess.EssNature; import io.openems.api.doc.ChannelInfo; @@ -43,6 +44,7 @@ public class AcIsland extends Controller { private State currentState = State.UNKNOWN; private boolean isProducerDisconnected = false; private long timeProducerDisconnected; + private ThingStateChannels thingState = new ThingStateChannels(this); private enum State { OFFGRID, ONGRID, SWITCHTOOFFGRID, SWITCHTOONGRID, UNKNOWN @@ -289,4 +291,9 @@ private void switchOutput(WriteChannel outputChannel, boolean on,boolea outputChannel.pushWrite(on ^ invertOutput); } } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } } diff --git a/edge/src/io/openems/impl/controller/api/modbustcp/ModbusTcpApiController.java b/edge/src/io/openems/impl/controller/api/modbustcp/ModbusTcpApiController.java index d8097ba3bd3..ea95d47f140 100644 --- a/edge/src/io/openems/impl/controller/api/modbustcp/ModbusTcpApiController.java +++ b/edge/src/io/openems/impl/controller/api/modbustcp/ModbusTcpApiController.java @@ -11,6 +11,7 @@ import io.openems.api.channel.Channel; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.doc.ChannelDoc; import io.openems.api.doc.ChannelInfo; @@ -30,6 +31,7 @@ public class ModbusTcpApiController extends Controller { private Optional slaveOpt = Optional.empty(); private final ApiWorker apiWorker = new ApiWorker(); private final MyProcessImage processImage = new MyProcessImage(UNIT_ID, apiWorker); + private ThingStateChannels thingState = new ThingStateChannels(this); /* * Constructors @@ -137,4 +139,9 @@ protected void updateChannelMapping(Optional jMappingOpt) { } } } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } } \ No newline at end of file diff --git a/edge/src/io/openems/impl/controller/api/rest/RestApiController.java b/edge/src/io/openems/impl/controller/api/rest/RestApiController.java index ff4c391d014..8b7dfbc64b9 100644 --- a/edge/src/io/openems/impl/controller/api/rest/RestApiController.java +++ b/edge/src/io/openems/impl/controller/api/rest/RestApiController.java @@ -1,80 +1,87 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.api.rest; - -import java.util.Optional; - -import io.openems.api.channel.Channel; -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.OpenemsException; -import io.openems.core.utilities.api.ApiWorker; - -@ThingInfo(title = "REST-Api", description = "Use for external access to OpenEMS.") -public class RestApiController extends Controller { - - private final ApiWorker apiWorker = new ApiWorker(); - - /* - * Constructors - */ - public RestApiController() { - super(); - } - - public RestApiController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Port", description = "Sets the port of the REST-Api Server.", type = Integer.class, defaultValue = "8084") - public final ConfigChannel port = new ConfigChannel("port", this); - - @ChannelInfo(title = "ChannelTimeout", description = "Sets the timeout for updates to channels.", type = Integer.class, defaultValue = "" - + ApiWorker.DEFAULT_TIMEOUT_SECONDS) - public final ConfigChannel channelTimeout = new ConfigChannel("channelTimeout", this) - .addChangeListener((Channel channel, Optional newValue, Optional oldValue) -> { - if (newValue.isPresent() && Integer.parseInt(newValue.get().toString()) >= 0) { - apiWorker.setTimeoutSeconds(Integer.parseInt(newValue.get().toString())); - } else { - apiWorker.setTimeoutSeconds(ApiWorker.DEFAULT_TIMEOUT_SECONDS); - } - }); - - /* - * Methods - */ - @Override - public void run() { - // Start REST-Api server - try { - ComponentSingleton.getComponent(this.port, this.apiWorker); - } catch (OpenemsException e) { - log.error(e.getMessage() + ": " + e.getCause()); - } - // API Worker - this.apiWorker.run(); - } -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.api.rest; + +import java.util.Optional; + +import io.openems.api.channel.Channel; +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.OpenemsException; +import io.openems.core.utilities.api.ApiWorker; + +@ThingInfo(title = "REST-Api", description = "Use for external access to OpenEMS.") +public class RestApiController extends Controller { + + private final ApiWorker apiWorker = new ApiWorker(); + private ThingStateChannels thingState = new ThingStateChannels(this); + + /* + * Constructors + */ + public RestApiController() { + super(); + } + + public RestApiController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Port", description = "Sets the port of the REST-Api Server.", type = Integer.class, defaultValue = "8084") + public final ConfigChannel port = new ConfigChannel("port", this); + + @ChannelInfo(title = "ChannelTimeout", description = "Sets the timeout for updates to channels.", type = Integer.class, defaultValue = "" + + ApiWorker.DEFAULT_TIMEOUT_SECONDS) + public final ConfigChannel channelTimeout = new ConfigChannel("channelTimeout", this) + .addChangeListener((Channel channel, Optional newValue, Optional oldValue) -> { + if (newValue.isPresent() && Integer.parseInt(newValue.get().toString()) >= 0) { + apiWorker.setTimeoutSeconds(Integer.parseInt(newValue.get().toString())); + } else { + apiWorker.setTimeoutSeconds(ApiWorker.DEFAULT_TIMEOUT_SECONDS); + } + }); + + /* + * Methods + */ + @Override + public void run() { + // Start REST-Api server + try { + ComponentSingleton.getComponent(this.port, this.apiWorker); + } catch (OpenemsException e) { + log.error(e.getMessage() + ": " + e.getCause()); + } + // API Worker + this.apiWorker.run(); + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } +} diff --git a/edge/src/io/openems/impl/controller/api/websocket/WebsocketApiController.java b/edge/src/io/openems/impl/controller/api/websocket/WebsocketApiController.java index 49c6746788f..8cdce4dc043 100644 --- a/edge/src/io/openems/impl/controller/api/websocket/WebsocketApiController.java +++ b/edge/src/io/openems/impl/controller/api/websocket/WebsocketApiController.java @@ -1,116 +1,123 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.api.websocket; - -import java.io.IOException; -import java.util.Optional; - -import io.openems.api.channel.Channel; -import io.openems.api.channel.ChannelChangeListener; -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.core.utilities.api.ApiWorker; - -@ThingInfo(title = "Websocket-API", description = "Required by OpenEMS-UI.") -public class WebsocketApiController extends Controller implements ChannelChangeListener { - - private final ApiWorker apiWorker = new ApiWorker(); - - /* - * Constructors - */ - public WebsocketApiController() { - super(); - } - - public WebsocketApiController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Port", description = "Sets the port of the Websocket-Api Server.", type = Integer.class, defaultValue = "8085") - public final ConfigChannel port = new ConfigChannel("port", this).addChangeListener(this); - - @ChannelInfo(title = "ChannelTimeout", description = "Sets the timeout for updates to channels.", type = Integer.class, defaultValue = "" - + ApiWorker.DEFAULT_TIMEOUT_SECONDS) - public final ConfigChannel channelTimeout = new ConfigChannel("channelTimeout", this) - .addChangeListener((Channel channel, Optional newValue, Optional oldValue) -> { - if(newValue.isPresent() && Integer.parseInt(newValue.get().toString()) >= 0) { - apiWorker.setTimeoutSeconds(Integer.parseInt(newValue.get().toString())); - } else { - apiWorker.setTimeoutSeconds(ApiWorker.DEFAULT_TIMEOUT_SECONDS); - } - }); - - /* - * Fields - */ - private volatile WebsocketApiServer websocketApiServer = null; - - /* - * Methods - */ - @Override - public void run() { - // Start Websocket-Api server - if (websocketApiServer == null && port.valueOptional().isPresent()) { - try { - websocketApiServer = new WebsocketApiServer(apiWorker, port.valueOptional().get()); - websocketApiServer.start(); - log.info("Websocket-Api started on port [" + port.valueOptional().orElse(0) + "]."); - } catch (Exception e) { - log.error(e.getMessage() + ": " + e.getCause()); - } - } - // call AapiWorker - this.apiWorker.run(); - } - - @Override - public void channelChanged(Channel channel, Optional newValue, Optional oldValue) { - if (channel.equals(port)) { - if (this.websocketApiServer != null) { - try { - this.websocketApiServer.stop(); - } catch (IOException | InterruptedException e) { - log.error("Error closing websocket on port [" + oldValue + "]: " + e.getMessage()); - } - } - this.websocketApiServer = null; - } - } - - /** - * Send a log entry to all connected websockets - * - * @param string - * @param timestamp - * - * @param jMessage - */ - public void broadcastLog(long timestamp, String level, String source, String message) { - this.websocketApiServer.broadcastLog(timestamp, level, source, message); - } -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.api.websocket; + +import java.io.IOException; +import java.util.Optional; + +import io.openems.api.channel.Channel; +import io.openems.api.channel.ChannelChangeListener; +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.core.utilities.api.ApiWorker; + +@ThingInfo(title = "Websocket-API", description = "Required by OpenEMS-UI.") +public class WebsocketApiController extends Controller implements ChannelChangeListener { + + private final ApiWorker apiWorker = new ApiWorker(); + private ThingStateChannels thingState = new ThingStateChannels(this); + + /* + * Constructors + */ + public WebsocketApiController() { + super(); + } + + public WebsocketApiController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Port", description = "Sets the port of the Websocket-Api Server.", type = Integer.class, defaultValue = "8085") + public final ConfigChannel port = new ConfigChannel("port", this).addChangeListener(this); + + @ChannelInfo(title = "ChannelTimeout", description = "Sets the timeout for updates to channels.", type = Integer.class, defaultValue = "" + + ApiWorker.DEFAULT_TIMEOUT_SECONDS) + public final ConfigChannel channelTimeout = new ConfigChannel("channelTimeout", this) + .addChangeListener((Channel channel, Optional newValue, Optional oldValue) -> { + if(newValue.isPresent() && Integer.parseInt(newValue.get().toString()) >= 0) { + apiWorker.setTimeoutSeconds(Integer.parseInt(newValue.get().toString())); + } else { + apiWorker.setTimeoutSeconds(ApiWorker.DEFAULT_TIMEOUT_SECONDS); + } + }); + + /* + * Fields + */ + private volatile WebsocketApiServer websocketApiServer = null; + + /* + * Methods + */ + @Override + public void run() { + // Start Websocket-Api server + if (websocketApiServer == null && port.valueOptional().isPresent()) { + try { + websocketApiServer = new WebsocketApiServer(apiWorker, port.valueOptional().get()); + websocketApiServer.start(); + log.info("Websocket-Api started on port [" + port.valueOptional().orElse(0) + "]."); + } catch (Exception e) { + log.error(e.getMessage() + ": " + e.getCause()); + } + } + // call AapiWorker + this.apiWorker.run(); + } + + @Override + public void channelChanged(Channel channel, Optional newValue, Optional oldValue) { + if (channel.equals(port)) { + if (this.websocketApiServer != null) { + try { + this.websocketApiServer.stop(); + } catch (IOException | InterruptedException e) { + log.error("Error closing websocket on port [" + oldValue + "]: " + e.getMessage()); + } + } + this.websocketApiServer = null; + } + } + + /** + * Send a log entry to all connected websockets + * + * @param string + * @param timestamp + * + * @param jMessage + */ + public void broadcastLog(long timestamp, String level, String source, String message) { + this.websocketApiServer.broadcastLog(timestamp, level, source, message); + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } +} diff --git a/edge/src/io/openems/impl/controller/asymmetric/avoidtotalcharge/AvoidTotalChargeController.java b/edge/src/io/openems/impl/controller/asymmetric/avoidtotalcharge/AvoidTotalChargeController.java index a17ea82c0ef..992ed9f1376 100644 --- a/edge/src/io/openems/impl/controller/asymmetric/avoidtotalcharge/AvoidTotalChargeController.java +++ b/edge/src/io/openems/impl/controller/asymmetric/avoidtotalcharge/AvoidTotalChargeController.java @@ -10,6 +10,7 @@ */ import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; @@ -19,6 +20,7 @@ @ThingInfo(title = "Avoid total charge of battery. (Asymmetric)", description = "Provides control over the battery's maximum state of charge at a specific time of day. For symmetric Ess.") public class AvoidTotalChargeController extends Controller { + private ThingStateChannels thingState = new ThingStateChannels(this); /* * Config */ @@ -168,4 +170,9 @@ private long getAsymmetricActivePower(long symmetricTotalActivePower, long gridM */ return (long) (((double)(gridMeterTotalActivePower + symmetricTotalActivePower) / (double) 3) - gridMeterActivePower); } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } } diff --git a/edge/src/io/openems/impl/controller/asymmetric/avoidtotaldischarge/AvoidTotalDischargeController.java b/edge/src/io/openems/impl/controller/asymmetric/avoidtotaldischarge/AvoidTotalDischargeController.java index dfb99303e4a..24604edb661 100644 --- a/edge/src/io/openems/impl/controller/asymmetric/avoidtotaldischarge/AvoidTotalDischargeController.java +++ b/edge/src/io/openems/impl/controller/asymmetric/avoidtotaldischarge/AvoidTotalDischargeController.java @@ -1,173 +1,180 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.asymmetric.avoidtotaldischarge; - -import java.util.Optional; -import java.util.Set; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.device.nature.ess.EssNature; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; -import io.openems.api.exception.WriteChannelException; -import io.openems.impl.controller.asymmetric.avoidtotaldischarge.Ess.State; - -@ThingInfo(title = "Avoid total discharge of battery (Asymmetric)", description = "Makes sure the battery is not going into critically low state of charge. For asymmetric Ess.") -public class AvoidTotalDischargeController extends Controller { - - /* - * Constructors - */ - public AvoidTotalDischargeController() { - super(); - } - - public AvoidTotalDischargeController(String id) { - super(id); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) - public final ConfigChannel> esss = new ConfigChannel>("esss", this); - @ChannelInfo(title = "Max Soc", description = "If the System is full the charge is blocked untill the soc decrease below the maxSoc.", type = Long.class, defaultValue = "95") - public final ConfigChannel maxSoc = new ConfigChannel("maxSoc", this); - - /* - * Methods - */ - @Override - public void run() { - try { - for (Ess ess : esss.value()) { - /* - * Calculate SetActivePower according to MinSoc - */ - switch (ess.currentState) { - case CHARGESOC: - if (ess.soc.value() > ess.minSoc.value()) { - ess.currentState = State.MINSOC; - } else { - try { - Optional currentMinValueL1 = ess.setActivePowerL1.writeMin(); - if (currentMinValueL1.isPresent() && currentMinValueL1.get() < 0) { - // Force Charge with minimum of MaxChargePower/5 - log.info("Force charge. Set ActivePowerL1=Max[" + currentMinValueL1.get() / 5 + "]"); - ess.setActivePowerL1.pushWriteMax(currentMinValueL1.get() / 5); - } else { - log.info("Avoid discharge. Set ActivePowerL1=Max[-1000 W]"); - ess.setActivePowerL1.pushWriteMax(-1000L); - } - } catch (WriteChannelException e) { - log.error("Unable to set ActivePowerL1: " + e.getMessage()); - } - try { - Optional currentMinValueL2 = ess.setActivePowerL2.writeMin(); - if (currentMinValueL2.isPresent() && currentMinValueL2.get() < 0) { - // Force Charge with minimum of MaxChargePower/5 - log.info("Force charge. Set ActivePowerL2=Max[" + currentMinValueL2.get() / 5 + "]"); - ess.setActivePowerL2.pushWriteMax(currentMinValueL2.get() / 5); - } else { - log.info("Avoid discharge. Set ActivePowerL2=Max[-1000 W]"); - ess.setActivePowerL2.pushWriteMax(-1000L); - } - } catch (WriteChannelException e) { - log.error("Unable to set ActivePowerL2: " + e.getMessage()); - } - try { - Optional currentMinValueL3 = ess.setActivePowerL3.writeMin(); - if (currentMinValueL3.isPresent() && currentMinValueL3.get() < 0) { - // Force Charge with minimum of MaxChargePower/5 - log.info("Force charge. Set ActivePowerL3=Max[" + currentMinValueL3.get() / 5 + "]"); - ess.setActivePowerL3.pushWriteMax(currentMinValueL3.get() / 5); - } else { - log.info("Avoid discharge. Set ActivePowerL3=Max[-1000 W]"); - ess.setActivePowerL3.pushWriteMax(-1000L); - } - } catch (WriteChannelException e) { - log.error("Unable to set ActivePowerL3: " + e.getMessage()); - } - } - break; - case MINSOC: - if (ess.soc.value() < ess.chargeSoc.value()) { - ess.currentState = State.CHARGESOC; - } else if (ess.soc.value() >= ess.minSoc.value() + 5) { - ess.currentState = State.NORMAL; - } else { - try { - long maxPower = 0; - if (!ess.setActivePowerL1.writeMax().isPresent() - || maxPower < ess.setActivePowerL1.writeMax().get()) { - ess.setActivePowerL1.pushWriteMax(maxPower); - } - if (!ess.setActivePowerL2.writeMax().isPresent() - || maxPower < ess.setActivePowerL2.writeMax().get()) { - ess.setActivePowerL2.pushWriteMax(maxPower); - } - if (!ess.setActivePowerL3.writeMax().isPresent() - || maxPower < ess.setActivePowerL3.writeMax().get()) { - ess.setActivePowerL3.pushWriteMax(maxPower); - } - } catch (WriteChannelException e) { - log.error(ess.id() + "Failed to set Max allowed power.", e); - } - } - break; - case NORMAL: - if (ess.soc.value() <= ess.minSoc.value()) { - ess.currentState = State.MINSOC; - } else if (ess.soc.value() >= 99 && ess.allowedCharge.value() == 0 - && ess.systemState.labelOptional().equals(Optional.of(EssNature.START))) { - ess.currentState = State.FULL; - } - break; - case FULL: - try { - ess.setActivePowerL1.pushWriteMin(0L); - } catch (WriteChannelException e) { - log.error("Unable to set ActivePowerL1: " + e.getMessage()); - } - try { - ess.setActivePowerL2.pushWriteMin(0L); - } catch (WriteChannelException e) { - log.error("Unable to set ActivePowerL2: " + e.getMessage()); - } - try { - ess.setActivePowerL3.pushWriteMin(0L); - } catch (WriteChannelException e) { - log.error("Unable to set ActivePowerL3: " + e.getMessage()); - } - if (ess.soc.value() < maxSoc.value()) { - ess.currentState = State.NORMAL; - } - break; - } - } - } catch (InvalidValueException e) { - log.error(e.getMessage()); - } - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.asymmetric.avoidtotaldischarge; + +import java.util.Optional; +import java.util.Set; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.device.nature.ess.EssNature; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.api.exception.WriteChannelException; +import io.openems.impl.controller.asymmetric.avoidtotaldischarge.Ess.State; + +@ThingInfo(title = "Avoid total discharge of battery (Asymmetric)", description = "Makes sure the battery is not going into critically low state of charge. For asymmetric Ess.") +public class AvoidTotalDischargeController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public AvoidTotalDischargeController() { + super(); + } + + public AvoidTotalDischargeController(String id) { + super(id); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) + public final ConfigChannel> esss = new ConfigChannel>("esss", this); + @ChannelInfo(title = "Max Soc", description = "If the System is full the charge is blocked untill the soc decrease below the maxSoc.", type = Long.class, defaultValue = "95") + public final ConfigChannel maxSoc = new ConfigChannel("maxSoc", this); + + /* + * Methods + */ + @Override + public void run() { + try { + for (Ess ess : esss.value()) { + /* + * Calculate SetActivePower according to MinSoc + */ + switch (ess.currentState) { + case CHARGESOC: + if (ess.soc.value() > ess.minSoc.value()) { + ess.currentState = State.MINSOC; + } else { + try { + Optional currentMinValueL1 = ess.setActivePowerL1.writeMin(); + if (currentMinValueL1.isPresent() && currentMinValueL1.get() < 0) { + // Force Charge with minimum of MaxChargePower/5 + log.info("Force charge. Set ActivePowerL1=Max[" + currentMinValueL1.get() / 5 + "]"); + ess.setActivePowerL1.pushWriteMax(currentMinValueL1.get() / 5); + } else { + log.info("Avoid discharge. Set ActivePowerL1=Max[-1000 W]"); + ess.setActivePowerL1.pushWriteMax(-1000L); + } + } catch (WriteChannelException e) { + log.error("Unable to set ActivePowerL1: " + e.getMessage()); + } + try { + Optional currentMinValueL2 = ess.setActivePowerL2.writeMin(); + if (currentMinValueL2.isPresent() && currentMinValueL2.get() < 0) { + // Force Charge with minimum of MaxChargePower/5 + log.info("Force charge. Set ActivePowerL2=Max[" + currentMinValueL2.get() / 5 + "]"); + ess.setActivePowerL2.pushWriteMax(currentMinValueL2.get() / 5); + } else { + log.info("Avoid discharge. Set ActivePowerL2=Max[-1000 W]"); + ess.setActivePowerL2.pushWriteMax(-1000L); + } + } catch (WriteChannelException e) { + log.error("Unable to set ActivePowerL2: " + e.getMessage()); + } + try { + Optional currentMinValueL3 = ess.setActivePowerL3.writeMin(); + if (currentMinValueL3.isPresent() && currentMinValueL3.get() < 0) { + // Force Charge with minimum of MaxChargePower/5 + log.info("Force charge. Set ActivePowerL3=Max[" + currentMinValueL3.get() / 5 + "]"); + ess.setActivePowerL3.pushWriteMax(currentMinValueL3.get() / 5); + } else { + log.info("Avoid discharge. Set ActivePowerL3=Max[-1000 W]"); + ess.setActivePowerL3.pushWriteMax(-1000L); + } + } catch (WriteChannelException e) { + log.error("Unable to set ActivePowerL3: " + e.getMessage()); + } + } + break; + case MINSOC: + if (ess.soc.value() < ess.chargeSoc.value()) { + ess.currentState = State.CHARGESOC; + } else if (ess.soc.value() >= ess.minSoc.value() + 5) { + ess.currentState = State.NORMAL; + } else { + try { + long maxPower = 0; + if (!ess.setActivePowerL1.writeMax().isPresent() + || maxPower < ess.setActivePowerL1.writeMax().get()) { + ess.setActivePowerL1.pushWriteMax(maxPower); + } + if (!ess.setActivePowerL2.writeMax().isPresent() + || maxPower < ess.setActivePowerL2.writeMax().get()) { + ess.setActivePowerL2.pushWriteMax(maxPower); + } + if (!ess.setActivePowerL3.writeMax().isPresent() + || maxPower < ess.setActivePowerL3.writeMax().get()) { + ess.setActivePowerL3.pushWriteMax(maxPower); + } + } catch (WriteChannelException e) { + log.error(ess.id() + "Failed to set Max allowed power.", e); + } + } + break; + case NORMAL: + if (ess.soc.value() <= ess.minSoc.value()) { + ess.currentState = State.MINSOC; + } else if (ess.soc.value() >= 99 && ess.allowedCharge.value() == 0 + && ess.systemState.labelOptional().equals(Optional.of(EssNature.START))) { + ess.currentState = State.FULL; + } + break; + case FULL: + try { + ess.setActivePowerL1.pushWriteMin(0L); + } catch (WriteChannelException e) { + log.error("Unable to set ActivePowerL1: " + e.getMessage()); + } + try { + ess.setActivePowerL2.pushWriteMin(0L); + } catch (WriteChannelException e) { + log.error("Unable to set ActivePowerL2: " + e.getMessage()); + } + try { + ess.setActivePowerL3.pushWriteMin(0L); + } catch (WriteChannelException e) { + log.error("Unable to set ActivePowerL3: " + e.getMessage()); + } + if (ess.soc.value() < maxSoc.value()) { + ess.currentState = State.NORMAL; + } + break; + } + } + } catch (InvalidValueException e) { + log.error(e.getMessage()); + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/asymmetric/balancing/BalancingController.java b/edge/src/io/openems/impl/controller/asymmetric/balancing/BalancingController.java index 0954fe54a10..f622fd76391 100644 --- a/edge/src/io/openems/impl/controller/asymmetric/balancing/BalancingController.java +++ b/edge/src/io/openems/impl/controller/asymmetric/balancing/BalancingController.java @@ -25,8 +25,8 @@ import java.util.Optional; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; -import io.openems.api.device.nature.ess.EssNature; import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; import io.openems.api.exception.InvalidValueException; @@ -36,6 +36,7 @@ @ThingInfo(title = "Self-consumption optimization (Asymmetric)", description = "Tries to keep the grid meter on zero. For asymmetric Ess.") public class BalancingController extends Controller { + private ThingStateChannels thingState = new ThingStateChannels(this); /* * Constructors */ @@ -71,9 +72,6 @@ public BalancingController(String thingId) { @Override public void run() { try { - for (Ess ess : esss.value()) { - ess.setWorkState.pushWriteFromLabel(EssNature.START); - } long[] calculatedPowers = new long[3]; long calculatedPowerSum = 0; // calculateRequiredPower @@ -325,4 +323,9 @@ private Tupel(T a, T b) { } } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/controller/asymmetric/balancingBandgap/BalancingBandgapActivePowerController.java b/edge/src/io/openems/impl/controller/asymmetric/balancingBandgap/BalancingBandgapActivePowerController.java index 01c5f084bf0..998942fe526 100644 --- a/edge/src/io/openems/impl/controller/asymmetric/balancingBandgap/BalancingBandgapActivePowerController.java +++ b/edge/src/io/openems/impl/controller/asymmetric/balancingBandgap/BalancingBandgapActivePowerController.java @@ -21,6 +21,7 @@ package io.openems.impl.controller.asymmetric.balancingBandgap; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; @@ -32,6 +33,7 @@ @ThingInfo(title = "Self-consumption optimization (Asymmetric)", description = "Tries to keep the grid meter on zero. For asymmetric Ess.") public class BalancingBandgapActivePowerController extends Controller { + private ThingStateChannels thingState = new ThingStateChannels(this); /* * Constructors */ @@ -134,4 +136,9 @@ public void run() { } } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/controller/asymmetric/balancingBandgap/BalancingBandgapReactivePowerController.java b/edge/src/io/openems/impl/controller/asymmetric/balancingBandgap/BalancingBandgapReactivePowerController.java index 91782aff9c5..6525959ef78 100644 --- a/edge/src/io/openems/impl/controller/asymmetric/balancingBandgap/BalancingBandgapReactivePowerController.java +++ b/edge/src/io/openems/impl/controller/asymmetric/balancingBandgap/BalancingBandgapReactivePowerController.java @@ -21,6 +21,7 @@ package io.openems.impl.controller.asymmetric.balancingBandgap; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; @@ -32,6 +33,7 @@ @ThingInfo(title = "Self-consumption optimization (Asymmetric)", description = "Tries to keep the grid meter on zero. For asymmetric Ess.") public class BalancingBandgapReactivePowerController extends Controller { + private ThingStateChannels thingState = new ThingStateChannels(this); /* * Constructors */ @@ -134,4 +136,9 @@ public void run() { } } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/controller/asymmetric/balancingcurrent/BalancingCurrentController.java b/edge/src/io/openems/impl/controller/asymmetric/balancingcurrent/BalancingCurrentController.java index e6742a2ce70..8eede4592d1 100644 --- a/edge/src/io/openems/impl/controller/asymmetric/balancingcurrent/BalancingCurrentController.java +++ b/edge/src/io/openems/impl/controller/asymmetric/balancingcurrent/BalancingCurrentController.java @@ -21,6 +21,7 @@ package io.openems.impl.controller.asymmetric.balancingcurrent; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; @@ -31,6 +32,7 @@ @ThingInfo(title = "Balancing current (Asymmetric)", description = "Tries to keep the grid meter at a given current. For asymmetric Ess.") public class BalancingCurrentController extends Controller { + private ThingStateChannels thingState = new ThingStateChannels(this); /* * Constructors */ @@ -91,4 +93,9 @@ public void run() { } } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/controller/asymmetric/capacitytest/CapacityTestController.java b/edge/src/io/openems/impl/controller/asymmetric/capacitytest/CapacityTestController.java index 68fe30c38b2..0e26849b896 100644 --- a/edge/src/io/openems/impl/controller/asymmetric/capacitytest/CapacityTestController.java +++ b/edge/src/io/openems/impl/controller/asymmetric/capacitytest/CapacityTestController.java @@ -1,144 +1,151 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.asymmetric.capacitytest; - -import java.io.FileWriter; -import java.io.IOException; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.List; -import java.util.Optional; - -import io.openems.api.channel.Channel; -import io.openems.api.channel.ChannelUpdateListener; -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.device.nature.ess.EssNature; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; -import io.openems.api.exception.WriteChannelException; - -@ThingInfo(title = "Battery capacity test (Asymmetric)", description = "Executes a capacity test. For asymmetric Ess.") -public class CapacityTestController extends Controller { - - /* - * Constructors - */ - public CapacityTestController() { - super(); - initialize(); - } - - public CapacityTestController(String thingId) { - super(thingId); - initialize(); - } - - /* - * Config - */ - @ChannelInfo(title = "Power", description = "Discharge power of Ess.", type = Integer.class, defaultValue = "750") - public ConfigChannel power = new ConfigChannel("power", this); - - @ChannelInfo(title = "Log-File", description = "Path to save the logfile.", type = String.class) - public ConfigChannel logPath = new ConfigChannel("logPath", this); - - @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) - public ConfigChannel> esss = new ConfigChannel>("esss", this); - - /* - * Fields - */ - private FileWriter fw; - - /* - * Methods - */ - private void initialize() { - logPath.addUpdateListener(new ChannelUpdateListener() { - - @Override - public void channelUpdated(Channel channel, Optional newValue) { - try { - if (fw != null) { - fw.close(); - } - fw = new FileWriter(logPath.value()); - fw.write("time;activePowerL1;activePowerL2;activePowerL3;soc\n"); - } catch (IOException e) { - log.error(e.getMessage()); - } catch (InvalidValueException e) { - log.error(e.getMessage()); - } - - } - }); - } - - @Override - public void run() { - try { - for (Ess ess : esss.value()) { - ess.setWorkState.pushWriteFromLabel(EssNature.START); - if (ess.empty) { - // Capacitytest - if (ess.full) { - // fully discharge ess - ess.setActivePowerL1.pushWrite((long) power.value()); - ess.setActivePowerL2.pushWrite((long) power.value()); - ess.setActivePowerL3.pushWrite((long) power.value()); - } else { - // fully charge ess - ess.setActivePowerL1.pushWrite((long) power.value() * -1); - ess.setActivePowerL2.pushWrite((long) power.value() * -1); - ess.setActivePowerL3.pushWrite((long) power.value() * -1); - if (ess.allowedCharge.value() <= 100l - && ess.systemState.labelOptional().equals(Optional.of(EssNature.START))) { - ess.full = true; - } - } - fw.append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + ";" - + ess.activePowerL1.value() + ";" + ess.activePowerL2.value() + ";" - + ess.activePowerL3.value() + ";" + ess.soc.value() + "\n"); - fw.flush(); - } else { - // prepare for capacityTest - // Empty ess - ess.setActivePowerL1.pushWrite(ess.allowedDischarge.value() / 3); - ess.setActivePowerL2.pushWrite(ess.allowedDischarge.value() / 3); - ess.setActivePowerL3.pushWrite(ess.allowedDischarge.value() / 3); - if (ess.allowedDischarge.value() <= 100l - && ess.systemState.labelOptional().equals(Optional.of(EssNature.START))) { - ess.empty = true; - } - } - } - } catch (InvalidValueException e) { - log.error(e.getMessage()); - } catch (WriteChannelException e) { - log.error(e.getMessage()); - } catch (IOException e) { - log.error(e.getMessage()); - } - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.asymmetric.capacitytest; + +import java.io.FileWriter; +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Optional; + +import io.openems.api.channel.Channel; +import io.openems.api.channel.ChannelUpdateListener; +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.device.nature.ess.EssNature; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.api.exception.WriteChannelException; + +@ThingInfo(title = "Battery capacity test (Asymmetric)", description = "Executes a capacity test. For asymmetric Ess.") +public class CapacityTestController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public CapacityTestController() { + super(); + initialize(); + } + + public CapacityTestController(String thingId) { + super(thingId); + initialize(); + } + + /* + * Config + */ + @ChannelInfo(title = "Power", description = "Discharge power of Ess.", type = Integer.class, defaultValue = "750") + public ConfigChannel power = new ConfigChannel("power", this); + + @ChannelInfo(title = "Log-File", description = "Path to save the logfile.", type = String.class) + public ConfigChannel logPath = new ConfigChannel("logPath", this); + + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) + public ConfigChannel> esss = new ConfigChannel>("esss", this); + + /* + * Fields + */ + private FileWriter fw; + + /* + * Methods + */ + private void initialize() { + logPath.addUpdateListener(new ChannelUpdateListener() { + + @Override + public void channelUpdated(Channel channel, Optional newValue) { + try { + if (fw != null) { + fw.close(); + } + fw = new FileWriter(logPath.value()); + fw.write("time;activePowerL1;activePowerL2;activePowerL3;soc\n"); + } catch (IOException e) { + log.error(e.getMessage()); + } catch (InvalidValueException e) { + log.error(e.getMessage()); + } + + } + }); + } + + @Override + public void run() { + try { + for (Ess ess : esss.value()) { + ess.setWorkState.pushWriteFromLabel(EssNature.START); + if (ess.empty) { + // Capacitytest + if (ess.full) { + // fully discharge ess + ess.setActivePowerL1.pushWrite((long) power.value()); + ess.setActivePowerL2.pushWrite((long) power.value()); + ess.setActivePowerL3.pushWrite((long) power.value()); + } else { + // fully charge ess + ess.setActivePowerL1.pushWrite((long) power.value() * -1); + ess.setActivePowerL2.pushWrite((long) power.value() * -1); + ess.setActivePowerL3.pushWrite((long) power.value() * -1); + if (ess.allowedCharge.value() <= 100l + && ess.systemState.labelOptional().equals(Optional.of(EssNature.START))) { + ess.full = true; + } + } + fw.append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + ";" + + ess.activePowerL1.value() + ";" + ess.activePowerL2.value() + ";" + + ess.activePowerL3.value() + ";" + ess.soc.value() + "\n"); + fw.flush(); + } else { + // prepare for capacityTest + // Empty ess + ess.setActivePowerL1.pushWrite(ess.allowedDischarge.value() / 3); + ess.setActivePowerL2.pushWrite(ess.allowedDischarge.value() / 3); + ess.setActivePowerL3.pushWrite(ess.allowedDischarge.value() / 3); + if (ess.allowedDischarge.value() <= 100l + && ess.systemState.labelOptional().equals(Optional.of(EssNature.START))) { + ess.empty = true; + } + } + } + } catch (InvalidValueException e) { + log.error(e.getMessage()); + } catch (WriteChannelException e) { + log.error(e.getMessage()); + } catch (IOException e) { + log.error(e.getMessage()); + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/asymmetric/fixvalue/FixValueActivePowerController.java b/edge/src/io/openems/impl/controller/asymmetric/fixvalue/FixValueActivePowerController.java index 91f7b8b4b55..12b21b6d39b 100644 --- a/edge/src/io/openems/impl/controller/asymmetric/fixvalue/FixValueActivePowerController.java +++ b/edge/src/io/openems/impl/controller/asymmetric/fixvalue/FixValueActivePowerController.java @@ -23,6 +23,7 @@ import java.util.Set; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; @@ -33,6 +34,7 @@ @ThingInfo(title = "Fixed active and reactive power (Asymmetric)", description = "Charges or discharges the battery with a predefined, fixed power. For asymmetric Ess.") public class FixValueActivePowerController extends Controller { + private ThingStateChannels thingState = new ThingStateChannels(this); /* * Constructors */ @@ -76,4 +78,9 @@ public void run() { } } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/controller/asymmetric/fixvalue/FixValueReactivePowerController.java b/edge/src/io/openems/impl/controller/asymmetric/fixvalue/FixValueReactivePowerController.java index 918b35b3a03..86bbb185470 100644 --- a/edge/src/io/openems/impl/controller/asymmetric/fixvalue/FixValueReactivePowerController.java +++ b/edge/src/io/openems/impl/controller/asymmetric/fixvalue/FixValueReactivePowerController.java @@ -1,75 +1,82 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.asymmetric.fixvalue; - -import java.util.Set; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; - -@ThingInfo(title = "Fixed active and reactive power (Asymmetric)", description = "Charges or discharges the battery with a predefined, fixed power. For asymmetric Ess.") -public class FixValueReactivePowerController extends Controller { - - /* - * Constructors - */ - public FixValueReactivePowerController() { - super(); - } - - public FixValueReactivePowerController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) - public final ConfigChannel> esss = new ConfigChannel>("esss", this); - - @ChannelInfo(title = "ReactivePower L1", description = "Fixed reactive power for phase L1.", type = Long.class) - public final ConfigChannel reactivePowerL1 = new ConfigChannel<>("reactivePowerL1", this); - - @ChannelInfo(title = "ReactivePower L2", description = "Fixed reactive power for phase L2.", type = Long.class) - public final ConfigChannel reactivePowerL2 = new ConfigChannel<>("reactivePowerL2", this); - - @ChannelInfo(title = "ReactivePower L3", description = "Fixed reactive power for phase L3.", type = Long.class) - public final ConfigChannel reactivePowerL3 = new ConfigChannel<>("reactivePowerL3", this); - - /* - * Methods - */ - @Override - public void run() { - try { - for (Ess ess : esss.value()) { - ess.power.setReactivePower(reactivePowerL1.value(), reactivePowerL2.value(), reactivePowerL3.value()); - } - } catch (InvalidValueException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.asymmetric.fixvalue; + +import java.util.Set; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; + +@ThingInfo(title = "Fixed active and reactive power (Asymmetric)", description = "Charges or discharges the battery with a predefined, fixed power. For asymmetric Ess.") +public class FixValueReactivePowerController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public FixValueReactivePowerController() { + super(); + } + + public FixValueReactivePowerController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) + public final ConfigChannel> esss = new ConfigChannel>("esss", this); + + @ChannelInfo(title = "ReactivePower L1", description = "Fixed reactive power for phase L1.", type = Long.class) + public final ConfigChannel reactivePowerL1 = new ConfigChannel<>("reactivePowerL1", this); + + @ChannelInfo(title = "ReactivePower L2", description = "Fixed reactive power for phase L2.", type = Long.class) + public final ConfigChannel reactivePowerL2 = new ConfigChannel<>("reactivePowerL2", this); + + @ChannelInfo(title = "ReactivePower L3", description = "Fixed reactive power for phase L3.", type = Long.class) + public final ConfigChannel reactivePowerL3 = new ConfigChannel<>("reactivePowerL3", this); + + /* + * Methods + */ + @Override + public void run() { + try { + for (Ess ess : esss.value()) { + ess.power.setReactivePower(reactivePowerL1.value(), reactivePowerL2.value(), reactivePowerL3.value()); + } + } catch (InvalidValueException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/asymmetric/phaserectification/PhaseRectificationActivePowerController.java b/edge/src/io/openems/impl/controller/asymmetric/phaserectification/PhaseRectificationActivePowerController.java index 6e0c247cd54..5a199045a99 100644 --- a/edge/src/io/openems/impl/controller/asymmetric/phaserectification/PhaseRectificationActivePowerController.java +++ b/edge/src/io/openems/impl/controller/asymmetric/phaserectification/PhaseRectificationActivePowerController.java @@ -1,6 +1,7 @@ package io.openems.impl.controller.asymmetric.phaserectification; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; @@ -12,6 +13,8 @@ @ThingInfo(title = "PhaseRectificationActivePowerController", description = "Sets the ess to the required activepower to get all three phases on the meter to the same level.") public class PhaseRectificationActivePowerController extends Controller { + private ThingStateChannels thingState = new ThingStateChannels(this); + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class) public ConfigChannel ess = new ConfigChannel("ess", this); @@ -68,4 +71,9 @@ public void run() { } } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/controller/asymmetric/phaserectification/PhaseRectificationReactivePowerController.java b/edge/src/io/openems/impl/controller/asymmetric/phaserectification/PhaseRectificationReactivePowerController.java index efd65dcebb5..d32b3d4b39c 100644 --- a/edge/src/io/openems/impl/controller/asymmetric/phaserectification/PhaseRectificationReactivePowerController.java +++ b/edge/src/io/openems/impl/controller/asymmetric/phaserectification/PhaseRectificationReactivePowerController.java @@ -1,6 +1,7 @@ package io.openems.impl.controller.asymmetric.phaserectification; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; @@ -11,6 +12,8 @@ @ThingInfo(title = "PhaseRectificationReactivePowerController", description = "Sets the ess to the required reactivepower to get all three phases on the meter to the same level.") public class PhaseRectificationReactivePowerController extends Controller { + private ThingStateChannels thingState = new ThingStateChannels(this); + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class) public ConfigChannel ess = new ConfigChannel("ess", this); @@ -56,4 +59,9 @@ public void run() { } } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/controller/asymmetric/powerlimitation/PowerLimitationController.java b/edge/src/io/openems/impl/controller/asymmetric/powerlimitation/PowerLimitationController.java index b6a1ed69bfd..eaf55ca3b7e 100644 --- a/edge/src/io/openems/impl/controller/asymmetric/powerlimitation/PowerLimitationController.java +++ b/edge/src/io/openems/impl/controller/asymmetric/powerlimitation/PowerLimitationController.java @@ -1,157 +1,164 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.asymmetric.powerlimitation; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; -import io.openems.api.exception.WriteChannelException; - -@ThingInfo(title = "Power limitation (Asymmetric)", description = "Limits the active and reactive power of the Ess. For Asymmetric Ess.") -public class PowerLimitationController extends Controller { - - /* - * Constructors - */ - public PowerLimitationController() { - super(); - } - - public PowerLimitationController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class) - public ConfigChannel ess = new ConfigChannel("ess", this); - - @ChannelInfo(title = "Min-Charge ActivePower", description = "The minimum allowed active power for discharge. Value is negative.", type = Long.class) - public ConfigChannel pMin = new ConfigChannel("pMin", this); - - @ChannelInfo(title = "Max-Charge ActivePower", description = "The maximum allowed active power for discharge. Value is positive.", type = Long.class) - public ConfigChannel pMax = new ConfigChannel("pMax", this); - - @ChannelInfo(title = "Min-Charge ReactivePower", description = "The minimum allowed reactive power for discharge. Value is negative.", type = Long.class) - public ConfigChannel qMin = new ConfigChannel("qMin", this); - - @ChannelInfo(title = "Max-Charge ReactivePower", description = "The maximum allowed reactive power for discharge. Value is positive.", type = Long.class) - public ConfigChannel qMax = new ConfigChannel("qMax", this); - - /* - * Methods - */ - @Override - public void run() { - try { - try { - if (pMax.value() < ess.value().setActivePowerL1.writeMax().orElse(Long.MAX_VALUE)) { - ess.value().setActivePowerL1.pushWriteMax(pMax.value()); - } - } catch (WriteChannelException | InvalidValueException e) { - log.error("Failed to write Max P value for [" + ess.value().id + "]: " + e.getMessage()); - } - try { - if (pMin.value() > ess.value().setActivePowerL1.writeMin().orElse(Long.MIN_VALUE)) { - ess.value().setActivePowerL1.pushWriteMin(pMin.value()); - } - } catch (WriteChannelException | InvalidValueException e) { - log.error("Failed to write Min P value for [" + ess.value().id + "]: " + e.getMessage()); - } - try { - if (qMin.value() > ess.value().setReactivePowerL1.writeMin().orElse(Long.MIN_VALUE)) { - ess.value().setReactivePowerL1.pushWriteMin(qMin.value()); - } - } catch (WriteChannelException | InvalidValueException e) { - log.error("Failed to write Min Q value for [" + ess.value().id + "]: " + e.getMessage()); - } - try { - if (qMax.value() < ess.value().setReactivePowerL1.writeMax().orElse(Long.MAX_VALUE)) { - ess.value().setReactivePowerL1.pushWriteMax(qMax.value()); - } - } catch (WriteChannelException | InvalidValueException e) { - log.error("Failed to write Max Q value for [" + ess.value().id + "]: " + e.getMessage()); - } - try { - if (pMax.value() < ess.value().setActivePowerL2.writeMax().orElse(Long.MAX_VALUE)) { - ess.value().setActivePowerL2.pushWriteMax(pMax.value()); - } - } catch (WriteChannelException | InvalidValueException e) { - log.error("Failed to write Max P value for [" + ess.value().id + "]: " + e.getMessage()); - } - try { - if (pMin.value() > ess.value().setActivePowerL2.writeMin().orElse(Long.MIN_VALUE)) { - ess.value().setActivePowerL2.pushWriteMin(pMin.value()); - } - } catch (WriteChannelException | InvalidValueException e) { - log.error("Failed to write Min P value for [" + ess.value().id + "]: " + e.getMessage()); - } - try { - if (qMin.value() > ess.value().setReactivePowerL2.writeMin().orElse(Long.MIN_VALUE)) { - ess.value().setReactivePowerL2.pushWriteMin(qMin.value()); - } - } catch (WriteChannelException | InvalidValueException e) { - log.error("Failed to write Min Q value for [" + ess.value().id + "]: " + e.getMessage()); - } - try { - if (qMax.value() < ess.value().setReactivePowerL2.writeMax().orElse(Long.MAX_VALUE)) { - ess.value().setReactivePowerL2.pushWriteMax(qMax.value()); - } - } catch (WriteChannelException | InvalidValueException e) { - log.error("Failed to write Max Q value for [" + ess.value().id + "]: " + e.getMessage()); - } - try { - if (pMax.value() < ess.value().setActivePowerL3.writeMax().orElse(Long.MAX_VALUE)) { - ess.value().setActivePowerL3.pushWriteMax(pMax.value()); - } - } catch (WriteChannelException | InvalidValueException e) { - log.error("Failed to write Max P value for [" + ess.value().id + "]: " + e.getMessage()); - } - try { - if (pMin.value() > ess.value().setActivePowerL3.writeMin().orElse(Long.MIN_VALUE)) { - ess.value().setActivePowerL3.pushWriteMin(pMin.value()); - } - } catch (WriteChannelException | InvalidValueException e) { - log.error("Failed to write Min P value for [" + ess.value().id + "]: " + e.getMessage()); - } - try { - if (qMin.value() > ess.value().setReactivePowerL3.writeMin().orElse(Long.MIN_VALUE)) { - ess.value().setReactivePowerL3.pushWriteMin(qMin.value()); - } - } catch (WriteChannelException | InvalidValueException e) { - log.error("Failed to write Min Q value for [" + ess.value().id + "]: " + e.getMessage()); - } - try { - if (qMax.value() < ess.value().setReactivePowerL3.writeMax().orElse(Long.MAX_VALUE)) { - ess.value().setReactivePowerL3.pushWriteMax(qMax.value()); - } - } catch (WriteChannelException | InvalidValueException e) { - log.error("Failed to write Max Q value for [" + ess.value().id + "]: " + e.getMessage()); - } - } catch (InvalidValueException e) { - log.error("No ess found.", e); - } - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.asymmetric.powerlimitation; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.api.exception.WriteChannelException; + +@ThingInfo(title = "Power limitation (Asymmetric)", description = "Limits the active and reactive power of the Ess. For Asymmetric Ess.") +public class PowerLimitationController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public PowerLimitationController() { + super(); + } + + public PowerLimitationController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class) + public ConfigChannel ess = new ConfigChannel("ess", this); + + @ChannelInfo(title = "Min-Charge ActivePower", description = "The minimum allowed active power for discharge. Value is negative.", type = Long.class) + public ConfigChannel pMin = new ConfigChannel("pMin", this); + + @ChannelInfo(title = "Max-Charge ActivePower", description = "The maximum allowed active power for discharge. Value is positive.", type = Long.class) + public ConfigChannel pMax = new ConfigChannel("pMax", this); + + @ChannelInfo(title = "Min-Charge ReactivePower", description = "The minimum allowed reactive power for discharge. Value is negative.", type = Long.class) + public ConfigChannel qMin = new ConfigChannel("qMin", this); + + @ChannelInfo(title = "Max-Charge ReactivePower", description = "The maximum allowed reactive power for discharge. Value is positive.", type = Long.class) + public ConfigChannel qMax = new ConfigChannel("qMax", this); + + /* + * Methods + */ + @Override + public void run() { + try { + try { + if (pMax.value() < ess.value().setActivePowerL1.writeMax().orElse(Long.MAX_VALUE)) { + ess.value().setActivePowerL1.pushWriteMax(pMax.value()); + } + } catch (WriteChannelException | InvalidValueException e) { + log.error("Failed to write Max P value for [" + ess.value().id + "]: " + e.getMessage()); + } + try { + if (pMin.value() > ess.value().setActivePowerL1.writeMin().orElse(Long.MIN_VALUE)) { + ess.value().setActivePowerL1.pushWriteMin(pMin.value()); + } + } catch (WriteChannelException | InvalidValueException e) { + log.error("Failed to write Min P value for [" + ess.value().id + "]: " + e.getMessage()); + } + try { + if (qMin.value() > ess.value().setReactivePowerL1.writeMin().orElse(Long.MIN_VALUE)) { + ess.value().setReactivePowerL1.pushWriteMin(qMin.value()); + } + } catch (WriteChannelException | InvalidValueException e) { + log.error("Failed to write Min Q value for [" + ess.value().id + "]: " + e.getMessage()); + } + try { + if (qMax.value() < ess.value().setReactivePowerL1.writeMax().orElse(Long.MAX_VALUE)) { + ess.value().setReactivePowerL1.pushWriteMax(qMax.value()); + } + } catch (WriteChannelException | InvalidValueException e) { + log.error("Failed to write Max Q value for [" + ess.value().id + "]: " + e.getMessage()); + } + try { + if (pMax.value() < ess.value().setActivePowerL2.writeMax().orElse(Long.MAX_VALUE)) { + ess.value().setActivePowerL2.pushWriteMax(pMax.value()); + } + } catch (WriteChannelException | InvalidValueException e) { + log.error("Failed to write Max P value for [" + ess.value().id + "]: " + e.getMessage()); + } + try { + if (pMin.value() > ess.value().setActivePowerL2.writeMin().orElse(Long.MIN_VALUE)) { + ess.value().setActivePowerL2.pushWriteMin(pMin.value()); + } + } catch (WriteChannelException | InvalidValueException e) { + log.error("Failed to write Min P value for [" + ess.value().id + "]: " + e.getMessage()); + } + try { + if (qMin.value() > ess.value().setReactivePowerL2.writeMin().orElse(Long.MIN_VALUE)) { + ess.value().setReactivePowerL2.pushWriteMin(qMin.value()); + } + } catch (WriteChannelException | InvalidValueException e) { + log.error("Failed to write Min Q value for [" + ess.value().id + "]: " + e.getMessage()); + } + try { + if (qMax.value() < ess.value().setReactivePowerL2.writeMax().orElse(Long.MAX_VALUE)) { + ess.value().setReactivePowerL2.pushWriteMax(qMax.value()); + } + } catch (WriteChannelException | InvalidValueException e) { + log.error("Failed to write Max Q value for [" + ess.value().id + "]: " + e.getMessage()); + } + try { + if (pMax.value() < ess.value().setActivePowerL3.writeMax().orElse(Long.MAX_VALUE)) { + ess.value().setActivePowerL3.pushWriteMax(pMax.value()); + } + } catch (WriteChannelException | InvalidValueException e) { + log.error("Failed to write Max P value for [" + ess.value().id + "]: " + e.getMessage()); + } + try { + if (pMin.value() > ess.value().setActivePowerL3.writeMin().orElse(Long.MIN_VALUE)) { + ess.value().setActivePowerL3.pushWriteMin(pMin.value()); + } + } catch (WriteChannelException | InvalidValueException e) { + log.error("Failed to write Min P value for [" + ess.value().id + "]: " + e.getMessage()); + } + try { + if (qMin.value() > ess.value().setReactivePowerL3.writeMin().orElse(Long.MIN_VALUE)) { + ess.value().setReactivePowerL3.pushWriteMin(qMin.value()); + } + } catch (WriteChannelException | InvalidValueException e) { + log.error("Failed to write Min Q value for [" + ess.value().id + "]: " + e.getMessage()); + } + try { + if (qMax.value() < ess.value().setReactivePowerL3.writeMax().orElse(Long.MAX_VALUE)) { + ess.value().setReactivePowerL3.pushWriteMax(qMax.value()); + } + } catch (WriteChannelException | InvalidValueException e) { + log.error("Failed to write Max Q value for [" + ess.value().id + "]: " + e.getMessage()); + } + } catch (InvalidValueException e) { + log.error("No ess found.", e); + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/asymmetricsymmetriccombination/AsymmetricSymmetricCombinationController.java b/edge/src/io/openems/impl/controller/asymmetricsymmetriccombination/AsymmetricSymmetricCombinationController.java index af5c738c258..a5384b8ac6f 100644 --- a/edge/src/io/openems/impl/controller/asymmetricsymmetriccombination/AsymmetricSymmetricCombinationController.java +++ b/edge/src/io/openems/impl/controller/asymmetricsymmetriccombination/AsymmetricSymmetricCombinationController.java @@ -1,6 +1,7 @@ package io.openems.impl.controller.asymmetricsymmetriccombination; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; @@ -10,6 +11,8 @@ @ThingInfo(title = "starts power calculation of AsymmetricSymmetricCombination Ess device") public class AsymmetricSymmetricCombinationController extends Controller { + private ThingStateChannels thingState = new ThingStateChannels(this); + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class) public final ConfigChannel ess = new ConfigChannel("ess", this); @@ -36,4 +39,11 @@ public void run() { } } + + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/controller/channelthreshold/ChannelThresholdController.java b/edge/src/io/openems/impl/controller/channelthreshold/ChannelThresholdController.java index 86d247d326b..35083d0abca 100644 --- a/edge/src/io/openems/impl/controller/channelthreshold/ChannelThresholdController.java +++ b/edge/src/io/openems/impl/controller/channelthreshold/ChannelThresholdController.java @@ -1,176 +1,183 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.channelthreshold; - -import java.util.Optional; - -import io.openems.api.channel.Channel; -import io.openems.api.channel.ConfigChannel; -import io.openems.api.channel.ReadChannel; -import io.openems.api.channel.WriteChannel; -import io.openems.api.controller.Controller; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; -import io.openems.api.exception.WriteChannelException; -import io.openems.core.ThingRepository; - -/* - * Example config: - *
- * {
- *   "class": "io.openems.impl.controller.channelthreshold.ChannelThresholdController",
- *   "priority": 65,
- *   "thresholdChannelAddress": "ess0/Soc",
- *   "outputChannelAddress": "output0/1",
- *   "lowerThreshold": 75,
- *   "upperThreshold": 80,
- *   "invertOutput": true
- * }
- * 
- */ - -@ThingInfo(title = "Switch channel on threshold") -public class ChannelThresholdController extends Controller { - - /* - * Constructors - */ - public ChannelThresholdController() { - super(); - } - - public ChannelThresholdController(String thingId) { - super(thingId); - } - - /* - * Fields - */ - private ThingRepository repo = ThingRepository.getInstance(); - private ReadChannel thresholdChannel; - private WriteChannel outputChannel; - private boolean isActive = false; - - /* - * Config - */ - @SuppressWarnings("unchecked") - @ChannelInfo(title = "Channel", description = "Address of the channel that indicates the switching by the min and max threshold.", type = String.class) - public ConfigChannel thresholdChannelName = new ConfigChannel("thresholdChannelAddress", this) - .addChangeListener((channel, newValue, oldValue) -> { - Optional channelAddress = (Optional) newValue; - if (channelAddress.isPresent()) { - Optional ch = repo.getChannelByAddress(channelAddress.get()); - if (ch.isPresent()) { - thresholdChannel = (ReadChannel) ch.get(); - } else { - log.error("Channel " + channelAddress.get() + " not found"); - } - } else { - log.error("'outputChannelAddress' is not configured!"); - } - }); - - @SuppressWarnings("unchecked") - @ChannelInfo(title = "Output", description = "Address of the digital output channel that should be switched.", type = String.class) - public ConfigChannel outputChannelName = new ConfigChannel("outputChannelAddress", this) - .addChangeListener((channel, newValue, oldValue) -> { - Optional channelAddress = (Optional) newValue; - if (channelAddress.isPresent()) { - Optional ch = repo.getChannelByAddress(channelAddress.get()); - if (ch.isPresent()) { - outputChannel = (WriteChannel) ch.get(); - } else { - log.error("Channel " + channelAddress.get() + " not found"); - } - } else { - log.error("'outputChannelAddress' is not configured!"); - } - }); - - @ChannelInfo(title = "Low threshold", description = "Low threshold where the output should be switched on.", type = Long.class) - public ConfigChannel lowerThreshold = new ConfigChannel("lowerThreshold", this); - - @ChannelInfo(title = "High threshold", description = "High threshold where the output should be switched off.", type = Long.class) - public ConfigChannel upperThreshold = new ConfigChannel("upperThreshold", this); - - @ChannelInfo(title = "Hysteresis", description = "Hysteresis for lower and upper threshold", type = Long.class) - public ConfigChannel hysteresis = new ConfigChannel("hysteresis", this); - - @ChannelInfo(title = "Invert-Output", description = "True if the digital output should be inverted.", type = Boolean.class) - public ConfigChannel invertOutput = new ConfigChannel("invertOutput", this).defaultValue(false); - - /* - * Methods - */ - @Override - public void run() { - // Check if all parameters are available - long threshold; - long lowerThreshold; - long upperThreshold; - long hysteresis; - boolean invertOutput; - try { - threshold = this.thresholdChannel.value(); - lowerThreshold = this.lowerThreshold.value(); - upperThreshold = this.upperThreshold.value(); - hysteresis = this.hysteresis.value(); - invertOutput = this.invertOutput.value(); - } catch (InvalidValueException e) { - log.error("ChannelThresholdController error: " + e.getMessage()); - return; - } - try { - if (isActive) { - if (threshold < lowerThreshold || threshold > upperThreshold + hysteresis) { - isActive = false; - } else { - on(invertOutput); - } - } else { - if (threshold >= lowerThreshold + hysteresis && threshold <= upperThreshold) { - isActive = true; - } else { - off(invertOutput); - } - } - } catch (WriteChannelException e) { - log.error("Failed to write Channel[" + outputChannel.address() + "]: " + e.getMessage()); - } - } - - private void on(boolean invertOutput) throws WriteChannelException { - Optional currentValueOpt = this.outputChannel.valueOptional(); - if (!currentValueOpt.isPresent() || currentValueOpt.get() != (true ^ invertOutput)) { - outputChannel.pushWrite(true ^ invertOutput); - } - } - - private void off(boolean invertOutput) throws WriteChannelException { - Optional currentValueOpt = this.outputChannel.valueOptional(); - if (!currentValueOpt.isPresent() || currentValueOpt.get() != (false ^ invertOutput)) { - outputChannel.pushWrite(false ^ invertOutput); - } - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.channelthreshold; + +import java.util.Optional; + +import io.openems.api.channel.Channel; +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.api.exception.WriteChannelException; +import io.openems.core.ThingRepository; + +/* + * Example config: + *
+ * {
+ *   "class": "io.openems.impl.controller.channelthreshold.ChannelThresholdController",
+ *   "priority": 65,
+ *   "thresholdChannelAddress": "ess0/Soc",
+ *   "outputChannelAddress": "output0/1",
+ *   "lowerThreshold": 75,
+ *   "upperThreshold": 80,
+ *   "invertOutput": true
+ * }
+ * 
+ */ + +@ThingInfo(title = "Switch channel on threshold") +public class ChannelThresholdController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public ChannelThresholdController() { + super(); + } + + public ChannelThresholdController(String thingId) { + super(thingId); + } + + /* + * Fields + */ + private ThingRepository repo = ThingRepository.getInstance(); + private ReadChannel thresholdChannel; + private WriteChannel outputChannel; + private boolean isActive = false; + + /* + * Config + */ + @SuppressWarnings("unchecked") + @ChannelInfo(title = "Channel", description = "Address of the channel that indicates the switching by the min and max threshold.", type = String.class) + public ConfigChannel thresholdChannelName = new ConfigChannel("thresholdChannelAddress", this) + .addChangeListener((channel, newValue, oldValue) -> { + Optional channelAddress = (Optional) newValue; + if (channelAddress.isPresent()) { + Optional ch = repo.getChannelByAddress(channelAddress.get()); + if (ch.isPresent()) { + thresholdChannel = (ReadChannel) ch.get(); + } else { + log.error("Channel " + channelAddress.get() + " not found"); + } + } else { + log.error("'outputChannelAddress' is not configured!"); + } + }); + + @SuppressWarnings("unchecked") + @ChannelInfo(title = "Output", description = "Address of the digital output channel that should be switched.", type = String.class) + public ConfigChannel outputChannelName = new ConfigChannel("outputChannelAddress", this) + .addChangeListener((channel, newValue, oldValue) -> { + Optional channelAddress = (Optional) newValue; + if (channelAddress.isPresent()) { + Optional ch = repo.getChannelByAddress(channelAddress.get()); + if (ch.isPresent()) { + outputChannel = (WriteChannel) ch.get(); + } else { + log.error("Channel " + channelAddress.get() + " not found"); + } + } else { + log.error("'outputChannelAddress' is not configured!"); + } + }); + + @ChannelInfo(title = "Low threshold", description = "Low threshold where the output should be switched on.", type = Long.class) + public ConfigChannel lowerThreshold = new ConfigChannel("lowerThreshold", this); + + @ChannelInfo(title = "High threshold", description = "High threshold where the output should be switched off.", type = Long.class) + public ConfigChannel upperThreshold = new ConfigChannel("upperThreshold", this); + + @ChannelInfo(title = "Hysteresis", description = "Hysteresis for lower and upper threshold", type = Long.class) + public ConfigChannel hysteresis = new ConfigChannel("hysteresis", this); + + @ChannelInfo(title = "Invert-Output", description = "True if the digital output should be inverted.", type = Boolean.class) + public ConfigChannel invertOutput = new ConfigChannel("invertOutput", this).defaultValue(false); + + /* + * Methods + */ + @Override + public void run() { + // Check if all parameters are available + long threshold; + long lowerThreshold; + long upperThreshold; + long hysteresis; + boolean invertOutput; + try { + threshold = this.thresholdChannel.value(); + lowerThreshold = this.lowerThreshold.value(); + upperThreshold = this.upperThreshold.value(); + hysteresis = this.hysteresis.value(); + invertOutput = this.invertOutput.value(); + } catch (InvalidValueException e) { + log.error("ChannelThresholdController error: " + e.getMessage()); + return; + } + try { + if (isActive) { + if (threshold < lowerThreshold || threshold > upperThreshold + hysteresis) { + isActive = false; + } else { + on(invertOutput); + } + } else { + if (threshold >= lowerThreshold + hysteresis && threshold <= upperThreshold) { + isActive = true; + } else { + off(invertOutput); + } + } + } catch (WriteChannelException e) { + log.error("Failed to write Channel[" + outputChannel.address() + "]: " + e.getMessage()); + } + } + + private void on(boolean invertOutput) throws WriteChannelException { + Optional currentValueOpt = this.outputChannel.valueOptional(); + if (!currentValueOpt.isPresent() || currentValueOpt.get() != (true ^ invertOutput)) { + outputChannel.pushWrite(true ^ invertOutput); + } + } + + private void off(boolean invertOutput) throws WriteChannelException { + Optional currentValueOpt = this.outputChannel.valueOptional(); + if (!currentValueOpt.isPresent() || currentValueOpt.get() != (false ^ invertOutput)) { + outputChannel.pushWrite(false ^ invertOutput); + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/chargerlimitation/ChargeLimitationController.java b/edge/src/io/openems/impl/controller/chargerlimitation/ChargeLimitationController.java index 1ad1f78fb13..586f0c3c5cf 100644 --- a/edge/src/io/openems/impl/controller/chargerlimitation/ChargeLimitationController.java +++ b/edge/src/io/openems/impl/controller/chargerlimitation/ChargeLimitationController.java @@ -1,67 +1,74 @@ -package io.openems.impl.controller.chargerlimitation; - -import java.util.List; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; - -@ThingInfo(title = "Limit battery charge from DC", description = "Limits the maximum charge of the battery from DC connected charger.") -public class ChargeLimitationController extends Controller { - - /* - * Constructors - */ - - public ChargeLimitationController() { - super(); - } - - public ChargeLimitationController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class) - public ConfigChannel ess = new ConfigChannel("ess", this); - - @ChannelInfo(title = "Chargers", description = "Sets the chargers.", type = Charger.class, isArray = true) - public ConfigChannel> chargers = new ConfigChannel<>("chargers", this); - - /* - * Methods - */ - @Override - public void run() { - // try { - // Ess ess = this.ess.value(); - // List chargers = this.chargers.value(); - // // calculate maximal chargePower - // float power = ess.allowedCharge.value() + ess.getWrittenActivePower(); - // if (power > 0) { - // float maxCurrent = 0l; - // for (Charger c : chargers) { - // maxCurrent += c.nominalCurrent.value(); - // } - // for (Charger c : chargers) { - // c.setPower(power / maxCurrent * c.nominalCurrent.value()); - // } - // ess.setMaxCharge(ess.allowedCharge.value() - power); - // } else { - // for (Charger c : chargers) { - // c.setPower(0); - // } - // } - // } catch (InvalidValueException e) { - // // TODO Auto-generated catch block - // e.printStackTrace(); - // } catch (WriteChannelException e) { - // // TODO Auto-generated catch block - // e.printStackTrace(); - // } - } - -} +package io.openems.impl.controller.chargerlimitation; + +import java.util.List; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; + +@ThingInfo(title = "Limit battery charge from DC", description = "Limits the maximum charge of the battery from DC connected charger.") +public class ChargeLimitationController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + + public ChargeLimitationController() { + super(); + } + + public ChargeLimitationController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class) + public ConfigChannel ess = new ConfigChannel("ess", this); + + @ChannelInfo(title = "Chargers", description = "Sets the chargers.", type = Charger.class, isArray = true) + public ConfigChannel> chargers = new ConfigChannel<>("chargers", this); + + /* + * Methods + */ + @Override + public void run() { + // try { + // Ess ess = this.ess.value(); + // List chargers = this.chargers.value(); + // // calculate maximal chargePower + // float power = ess.allowedCharge.value() + ess.getWrittenActivePower(); + // if (power > 0) { + // float maxCurrent = 0l; + // for (Charger c : chargers) { + // maxCurrent += c.nominalCurrent.value(); + // } + // for (Charger c : chargers) { + // c.setPower(power / maxCurrent * c.nominalCurrent.value()); + // } + // ess.setMaxCharge(ess.allowedCharge.value() - power); + // } else { + // for (Charger c : chargers) { + // c.setPower(0); + // } + // } + // } catch (InvalidValueException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } catch (WriteChannelException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/clocksync/ClockSyncController.java b/edge/src/io/openems/impl/controller/clocksync/ClockSyncController.java index bf61965d3bb..2e605e99029 100644 --- a/edge/src/io/openems/impl/controller/clocksync/ClockSyncController.java +++ b/edge/src/io/openems/impl/controller/clocksync/ClockSyncController.java @@ -1,114 +1,121 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.clocksync; - -import java.io.IOException; -import java.util.Calendar; -import java.util.Optional; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.WriteChannelException; - -@ThingInfo(title = "Sychronizes system clocks", description = "Synchronizes the sytem clocks of OpenEMS and a connected real-time clock device.") -public class ClockSyncController extends Controller { - - /* - * Constructors - */ - public ClockSyncController() { - super(); - } - - public ClockSyncController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Real-time clock", description = "Sets the real-time clock device.", type = RealTimeClock.class, isOptional = true) - public final ConfigChannel rtc = new ConfigChannel("rtc", this); - - /* - * Fields - */ - private boolean isDateSet = false; - - /* - * Methods - */ - @Override - public void run() { - if (isDateSet) { - // Set time only once in the beginning - return; - } - if (rtc.valueOptional().isPresent()) { - RealTimeClock r = rtc.valueOptional().get(); - Optional rtcYear = r.year.valueOptional(); - Optional rtcMonth = r.month.valueOptional(); - Optional rtcDay = r.day.valueOptional(); - Optional rtcHour = r.hour.valueOptional(); - Optional rtcMinute = r.hour.valueOptional(); - Optional rtcSecond = r.second.valueOptional(); - - if (rtcYear.isPresent() && rtcMonth.isPresent() && rtcDay.isPresent() && rtcHour.isPresent() - && rtcMinute.isPresent() && rtcSecond.isPresent()) { - - Calendar systemNow = Calendar.getInstance(); - int year = systemNow.get(Calendar.YEAR); - if (year < 2016) { - // System date is wrong -> set system date from RTC - log.info("Setting system time from RTC: " + rtc.id() + ": " + rtcYear.get() + "-" + rtcMonth.get() - + "-" + rtcDay.get() + " " + rtcHour.get() + ":" + rtcMinute.get() + ":" + rtcSecond.get()); - try { - Runtime.getRuntime() - .exec(new String[] { "/usr/bin/timedatectl", "set-time", "2016-10-11 13:13:16" }); - // process is running in a separate process from now... - } catch (IOException e) { - log.error("Error while setting system time: ", e); - } - } else { - // System date is correct -> set RTC from system date - log.info("Setting RTC from system time: " + rtc.id() + ": " + systemNow.get(Calendar.YEAR) + "-" - + systemNow.get(Calendar.MONTH) + "-" + systemNow.get(Calendar.DAY_OF_MONTH) + " " - + systemNow.get(Calendar.HOUR_OF_DAY) + ":" + systemNow.get(Calendar.MINUTE) + ":" - + systemNow.get(Calendar.SECOND)); - try { - r.year.pushWrite(Long.valueOf(systemNow.get(Calendar.YEAR))); - r.month.pushWrite(Long.valueOf(systemNow.get(Calendar.MONTH))); - r.day.pushWrite(Long.valueOf(systemNow.get(Calendar.DAY_OF_MONTH))); - r.hour.pushWrite(Long.valueOf(systemNow.get(Calendar.HOUR_OF_DAY))); - r.minute.pushWrite(Long.valueOf(systemNow.get(Calendar.MINUTE))); - r.second.pushWrite(Long.valueOf(systemNow.get(Calendar.SECOND))); - } catch (WriteChannelException e) { - log.error("Error while setting RTC time: ", e); - } - } - - isDateSet = true; - } - } - } -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.clocksync; + +import java.io.IOException; +import java.util.Calendar; +import java.util.Optional; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.WriteChannelException; + +@ThingInfo(title = "Sychronizes system clocks", description = "Synchronizes the sytem clocks of OpenEMS and a connected real-time clock device.") +public class ClockSyncController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public ClockSyncController() { + super(); + } + + public ClockSyncController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Real-time clock", description = "Sets the real-time clock device.", type = RealTimeClock.class, isOptional = true) + public final ConfigChannel rtc = new ConfigChannel("rtc", this); + + /* + * Fields + */ + private boolean isDateSet = false; + + /* + * Methods + */ + @Override + public void run() { + if (isDateSet) { + // Set time only once in the beginning + return; + } + if (rtc.valueOptional().isPresent()) { + RealTimeClock r = rtc.valueOptional().get(); + Optional rtcYear = r.year.valueOptional(); + Optional rtcMonth = r.month.valueOptional(); + Optional rtcDay = r.day.valueOptional(); + Optional rtcHour = r.hour.valueOptional(); + Optional rtcMinute = r.hour.valueOptional(); + Optional rtcSecond = r.second.valueOptional(); + + if (rtcYear.isPresent() && rtcMonth.isPresent() && rtcDay.isPresent() && rtcHour.isPresent() + && rtcMinute.isPresent() && rtcSecond.isPresent()) { + + Calendar systemNow = Calendar.getInstance(); + int year = systemNow.get(Calendar.YEAR); + if (year < 2016) { + // System date is wrong -> set system date from RTC + log.info("Setting system time from RTC: " + rtc.id() + ": " + rtcYear.get() + "-" + rtcMonth.get() + + "-" + rtcDay.get() + " " + rtcHour.get() + ":" + rtcMinute.get() + ":" + rtcSecond.get()); + try { + Runtime.getRuntime() + .exec(new String[] { "/usr/bin/timedatectl", "set-time", "2016-10-11 13:13:16" }); + // process is running in a separate process from now... + } catch (IOException e) { + log.error("Error while setting system time: ", e); + } + } else { + // System date is correct -> set RTC from system date + log.info("Setting RTC from system time: " + rtc.id() + ": " + systemNow.get(Calendar.YEAR) + "-" + + systemNow.get(Calendar.MONTH) + "-" + systemNow.get(Calendar.DAY_OF_MONTH) + " " + + systemNow.get(Calendar.HOUR_OF_DAY) + ":" + systemNow.get(Calendar.MINUTE) + ":" + + systemNow.get(Calendar.SECOND)); + try { + r.year.pushWrite(Long.valueOf(systemNow.get(Calendar.YEAR))); + r.month.pushWrite(Long.valueOf(systemNow.get(Calendar.MONTH))); + r.day.pushWrite(Long.valueOf(systemNow.get(Calendar.DAY_OF_MONTH))); + r.hour.pushWrite(Long.valueOf(systemNow.get(Calendar.HOUR_OF_DAY))); + r.minute.pushWrite(Long.valueOf(systemNow.get(Calendar.MINUTE))); + r.second.pushWrite(Long.valueOf(systemNow.get(Calendar.SECOND))); + } catch (WriteChannelException e) { + log.error("Error while setting RTC time: ", e); + } + } + + isDateSet = true; + } + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } +} diff --git a/edge/src/io/openems/impl/controller/debuglog/DebugLogController.java b/edge/src/io/openems/impl/controller/debuglog/DebugLogController.java index 1fb4da9388b..db556976f80 100644 --- a/edge/src/io/openems/impl/controller/debuglog/DebugLogController.java +++ b/edge/src/io/openems/impl/controller/debuglog/DebugLogController.java @@ -1,97 +1,104 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.debuglog; - -import java.util.Set; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; - -// TODO Access all relevant channels directly via ThingRepository - -@ThingInfo(title = "Output debugging information on systemlog") -public class DebugLogController extends Controller { - - /* - * Constructors - */ - public DebugLogController() { - super(); - } - - public DebugLogController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isOptional = true, isArray = true) - public final ConfigChannel> esss = new ConfigChannel>("esss", this); - - @ChannelInfo(title = "Meters", description = "Sets the meters.", type = Meter.class, isOptional = true, isArray = true) - public final ConfigChannel> meters = new ConfigChannel>("meters", this); - - @ChannelInfo(title = "Real-time clock", description = "Sets the real-time clock.", type = RealTimeClock.class, isOptional = true) - public final ConfigChannel rtc = new ConfigChannel("rtc", this); - - @ChannelInfo(title = "EVCSs", description = "Sets the evcs.", type = Evcs.class, isOptional = true, isArray = true) - public final ConfigChannel> evcss = new ConfigChannel>("evcss", this); - - /* - * Methods - */ - @Override - public void run() { - try { - StringBuilder b = new StringBuilder(); - if (meters.valueOptional().isPresent()) { - for (Meter meter : meters.value()) { - b.append(meter.toString()); - b.append(" "); - } - } - if (rtc.valueOptional().isPresent()) { - b.append(rtc.valueOptional().get().toString()); - b.append(" "); - } - if (esss.valueOptional().isPresent()) { - for (Ess ess : esss.value()) { - b.append(ess.toString()); - b.append(" "); - } - } - if (evcss.valueOptional().isPresent()) { - for (Evcs evcs : evcss.value()) { - b.append(evcs.toString()); - b.append(" "); - } - } - log.info(b.toString()); - } catch (InvalidValueException e) { - e.printStackTrace(); - } - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.debuglog; + +import java.util.Set; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; + +// TODO Access all relevant channels directly via ThingRepository + +@ThingInfo(title = "Output debugging information on systemlog") +public class DebugLogController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public DebugLogController() { + super(); + } + + public DebugLogController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isOptional = true, isArray = true) + public final ConfigChannel> esss = new ConfigChannel>("esss", this); + + @ChannelInfo(title = "Meters", description = "Sets the meters.", type = Meter.class, isOptional = true, isArray = true) + public final ConfigChannel> meters = new ConfigChannel>("meters", this); + + @ChannelInfo(title = "Real-time clock", description = "Sets the real-time clock.", type = RealTimeClock.class, isOptional = true) + public final ConfigChannel rtc = new ConfigChannel("rtc", this); + + @ChannelInfo(title = "EVCSs", description = "Sets the evcs.", type = Evcs.class, isOptional = true, isArray = true) + public final ConfigChannel> evcss = new ConfigChannel>("evcss", this); + + /* + * Methods + */ + @Override + public void run() { + try { + StringBuilder b = new StringBuilder(); + if (meters.valueOptional().isPresent()) { + for (Meter meter : meters.value()) { + b.append(meter.toString()); + b.append(" "); + } + } + if (rtc.valueOptional().isPresent()) { + b.append(rtc.valueOptional().get().toString()); + b.append(" "); + } + if (esss.valueOptional().isPresent()) { + for (Ess ess : esss.value()) { + b.append(ess.toString()); + b.append(" "); + } + } + if (evcss.valueOptional().isPresent()) { + for (Evcs evcs : evcss.value()) { + b.append(evcs.toString()); + b.append(" "); + } + } + log.info(b.toString()); + } catch (InvalidValueException e) { + e.printStackTrace(); + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/debuglog/Ess.java b/edge/src/io/openems/impl/controller/debuglog/Ess.java index 53938bc927a..5528f59362b 100644 --- a/edge/src/io/openems/impl/controller/debuglog/Ess.java +++ b/edge/src/io/openems/impl/controller/debuglog/Ess.java @@ -1,89 +1,99 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.debuglog; - -import io.openems.api.controller.IsThingMap; -import io.openems.api.controller.ThingMap; -import io.openems.api.device.nature.ess.AsymmetricEssNature; -import io.openems.api.device.nature.ess.EssNature; -import io.openems.api.device.nature.ess.SymmetricEssNature; - -@IsThingMap(type = EssNature.class) -public class Ess extends ThingMap { - - private final EssNature ess; - - public Ess(EssNature ess) { - super(ess); - this.ess = ess; - - ess.allowedCharge().required(); - ess.allowedDischarge().required(); - ess.minSoc().required(); - ess.soc().required(); - ess.systemState().required(); - - if (ess instanceof AsymmetricEssNature) { - AsymmetricEssNature e = (AsymmetricEssNature) ess; - e.activePowerL1().required(); - e.activePowerL2().required(); - e.activePowerL3().required(); - e.reactivePowerL1().required(); - e.reactivePowerL2().required(); - e.reactivePowerL3().required(); - } - if (ess instanceof SymmetricEssNature) { - SymmetricEssNature e = (SymmetricEssNature) ess; - e.activePower().required(); - e.reactivePower().required(); - } - } - - @Override public String toString() { - StringBuilder b = new StringBuilder(); - b.append(ess.id() + " [" + // - "SOC:" + ess.soc().format() + "|"); - if (ess instanceof SymmetricEssNature) { - SymmetricEssNature e = (SymmetricEssNature) ess; - b.append("L:" + e.activePower().format() + ";" + e.reactivePower().format()); - } - if (ess instanceof AsymmetricEssNature && ess instanceof SymmetricEssNature) { - b.append("|"); - } - if (ess instanceof AsymmetricEssNature) { - AsymmetricEssNature e = (AsymmetricEssNature) ess; - b.append("L1:" + e.activePowerL1().format() + ";" + e.reactivePowerL1().format() + "|" + // - "L2:" + e.activePowerL2().format() + ";" + e.reactivePowerL2().format() + "|" + // - "L3:" + e.activePowerL3().format() + ";" + e.reactivePowerL3().format()); - } - b.append("|" + // - "Allowed:" + ess.allowedCharge().format() + ";" + ess.allowedDischarge().format()); - b.append("|" + // - "GridMode:" + ess.gridMode().labelOptional().orElse("unknown")); - String warn = ess.warning().toString(); - if (!warn.equals("")) { - b.append("|Warn:" + ess.warning()); - } - b.append("]"); - return b.toString(); - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.debuglog; + +import java.util.List; +import java.util.stream.Collectors; + +import io.openems.api.channel.ThingStateChannel; +import io.openems.api.controller.IsThingMap; +import io.openems.api.controller.ThingMap; +import io.openems.api.device.nature.ess.AsymmetricEssNature; +import io.openems.api.device.nature.ess.EssNature; +import io.openems.api.device.nature.ess.SymmetricEssNature; + +@IsThingMap(type = EssNature.class) +public class Ess extends ThingMap { + + private final EssNature ess; + + public Ess(EssNature ess) { + super(ess); + this.ess = ess; + + ess.allowedCharge().required(); + ess.allowedDischarge().required(); + ess.minSoc().required(); + ess.soc().required(); + ess.systemState().required(); + + if (ess instanceof AsymmetricEssNature) { + AsymmetricEssNature e = (AsymmetricEssNature) ess; + e.activePowerL1().required(); + e.activePowerL2().required(); + e.activePowerL3().required(); + e.reactivePowerL1().required(); + e.reactivePowerL2().required(); + e.reactivePowerL3().required(); + } + if (ess instanceof SymmetricEssNature) { + SymmetricEssNature e = (SymmetricEssNature) ess; + e.activePower().required(); + e.reactivePower().required(); + } + } + + @Override public String toString() { + StringBuilder b = new StringBuilder(); + b.append(ess.id() + " [" + // + "SOC:" + ess.soc().format() + "|"); + if (ess instanceof SymmetricEssNature) { + SymmetricEssNature e = (SymmetricEssNature) ess; + b.append("L:" + e.activePower().format() + ";" + e.reactivePower().format()); + } + if (ess instanceof AsymmetricEssNature && ess instanceof SymmetricEssNature) { + b.append("|"); + } + if (ess instanceof AsymmetricEssNature) { + AsymmetricEssNature e = (AsymmetricEssNature) ess; + b.append("L1:" + e.activePowerL1().format() + ";" + e.reactivePowerL1().format() + "|" + // + "L2:" + e.activePowerL2().format() + ";" + e.reactivePowerL2().format() + "|" + // + "L3:" + e.activePowerL3().format() + ";" + e.reactivePowerL3().format()); + } + b.append("|" + // + "Allowed:" + ess.allowedCharge().format() + ";" + ess.allowedDischarge().format()); + b.append("|" + // + "GridMode:" + ess.gridMode().labelOptional().orElse("unknown")); + List warningChannels = ess.getStateChannel().getWarningChannels().stream().filter(c -> c.isValuePresent() && c.getValue()).collect(Collectors.toList()); + List faultChannels = ess.getStateChannel().getFaultChannels().stream().filter(c -> c.isValuePresent() && c.getValue()).collect(Collectors.toList()); + if(warningChannels.size() > 0) { + b.append("|Warn:"); + b.append(warningChannels.stream().map(c -> c.name()).collect(Collectors.joining())); + } + if(faultChannels.size() > 0) { + b.append("|Fault:"); + b.append(faultChannels.stream().map(c -> c.name()).collect(Collectors.joining())); + } + b.append("]"); + return b.toString(); + } + +} diff --git a/edge/src/io/openems/impl/controller/emergencygenerator/EmergencyGeneratorController.java b/edge/src/io/openems/impl/controller/emergencygenerator/EmergencyGeneratorController.java index 476f838c964..395aa9d82ab 100644 --- a/edge/src/io/openems/impl/controller/emergencygenerator/EmergencyGeneratorController.java +++ b/edge/src/io/openems/impl/controller/emergencygenerator/EmergencyGeneratorController.java @@ -1,173 +1,180 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.emergencygenerator; - -import java.util.Optional; - -import io.openems.api.channel.Channel; -import io.openems.api.channel.ConfigChannel; -import io.openems.api.channel.WriteChannel; -import io.openems.api.controller.Controller; -import io.openems.api.device.nature.ess.EssNature; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; -import io.openems.api.exception.WriteChannelException; -import io.openems.core.ThingRepository; - -@ThingInfo(title = "External generator control", description = "Starts an external generator in case of emergency.") -public class EmergencyGeneratorController extends Controller { - - /* - * Constructors - */ - public EmergencyGeneratorController() { - super(); - } - - public EmergencyGeneratorController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess device.", type = Ess.class) - public ConfigChannel ess = new ConfigChannel("ess", this); - - @ChannelInfo(title = "Grid-meter", description = "Sets the grid-meter to detect if the system is Off-Grid or On-Grid.", type = Meter.class) - public ConfigChannel meter = new ConfigChannel("meter", this); - - @ChannelInfo(title = "Min-SOC", description = "If the SOC falls under this value and the system is Off-Grid the generator starts.", type = Long.class) - public ConfigChannel minSoc = new ConfigChannel("minSoc", this); - - @ChannelInfo(title = "Max-SOC", description = "If the system is Off-Grid and the generator is running, the generator stops if the SOC level increases over the Max-SOC.", type = Long.class) - public ConfigChannel maxSoc = new ConfigChannel("maxSoc", this); - - @ChannelInfo(title = "Invert-Output", description = "True if the digital output should be inverted.", type = Boolean.class) - public ConfigChannel invertOutput = new ConfigChannel<>("invertOutput", this); - - @ChannelInfo(title = "On-Grid output on", description = "This value indicates if the system is On-Grid to start(true) or stop(false) the generator.", type = Boolean.class, isOptional = true) - public ConfigChannel onGridOutputOn = new ConfigChannel("onGridOutputOn", this) - .defaultValue(false); - - /* - * Fields - */ - private ThingRepository repo = ThingRepository.getInstance(); - private WriteChannel outputChannel; - private boolean generatorOn = false; - private long lastPower = 0l; - private Long cooldownStartTime = null; - - /* - * Methods - */ - @SuppressWarnings("unchecked") - @ChannelInfo(title = "the address of the Digital Output where the generator is connected to.", type = String.class) - public ConfigChannel outputChannelAddress = new ConfigChannel("outputChannelAddress", this) - .addChangeListener((channel, newValue, oldValue) -> { - Optional channelAddress = (Optional) newValue; - if (channelAddress.isPresent()) { - Optional ch = repo.getChannelByAddress(channelAddress.get()); - if (ch.isPresent()) { - outputChannel = (WriteChannel) ch.get(); - } else { - log.error("Channel " + channelAddress.get() + " not found"); - } - } else { - log.error("'outputChannelAddress' is not configured!"); - } - }); - - @Override - public void run() { - try { - // Check if grid is available - if (!meter.value().voltage.valueOptional().isPresent()) { - // no meassurable voltage => Off-Grid - if (ess.value().gridMode.labelOptional().equals(Optional.of(EssNature.OFF_GRID)) && !generatorOn - && ess.value().soc.value() <= minSoc.value()) { - // switch generator on - startGenerator(); - generatorOn = true; - System.out.println("1: storage is empty. Start generator."); - } else if (ess.value().gridMode.labelOptional().equals(Optional.of(EssNature.ON_GRID)) && generatorOn - && ess.value().soc.value() >= maxSoc.value()) { - // switch generator off - if (cooldownStartTime == null) { - cooldownStartTime = System.currentTimeMillis(); - ess.value().setActivePowerL1.pushWrite(0l); - ess.value().setActivePowerL2.pushWrite(0l); - ess.value().setActivePowerL3.pushWrite(0l); - log.info("Start cooldownphase."); - } else if (cooldownStartTime + 1000 * 60 < System.currentTimeMillis()) { - stopGenerator(); - generatorOn = false; - lastPower = 0l; - cooldownStartTime = null; - System.out.println("Storage is full. Stop generator."); - } - } else if (generatorOn) { - startGenerator(); - if (ess.value().gridMode.labelOptional().equals(Optional.of(EssNature.ON_GRID))) { - if (lastPower > -1000) { - lastPower -= 20l; - } - ess.value().setActivePowerL1.pushWrite(lastPower); - ess.value().setActivePowerL2.pushWrite(lastPower); - ess.value().setActivePowerL3.pushWrite(lastPower); - System.out.println("Charge with " + lastPower * 3 + " kW"); - } - System.out.println("3: "); - } else if (!generatorOn) { - stopGenerator(); - lastPower = 0l; - System.out.println("4: "); - } - } else { - // Grid voltage is in the allowed range - if (onGridOutputOn.value()) { - startGenerator(); - } else { - stopGenerator(); - } - } - } catch (InvalidValueException e) { - log.error("Failed to read value!", e); - } catch (WriteChannelException e) { - log.error("Error due write to output [" + outputChannelAddress.valueOptional().orElse("") + "]", e); - } - } - - private void startGenerator() throws WriteChannelException, InvalidValueException { - if (outputChannel.value() != true ^ invertOutput.value()) { - outputChannel.pushWrite(true ^ invertOutput.value()); - } - } - - private void stopGenerator() throws InvalidValueException, WriteChannelException { - if (outputChannel.value() != false ^ invertOutput.value()) { - outputChannel.pushWrite(false ^ invertOutput.value()); - } - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.emergencygenerator; + +import java.util.Optional; + +import io.openems.api.channel.Channel; +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.device.nature.ess.EssNature; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.api.exception.WriteChannelException; +import io.openems.core.ThingRepository; + +@ThingInfo(title = "External generator control", description = "Starts an external generator in case of emergency.") +public class EmergencyGeneratorController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public EmergencyGeneratorController() { + super(); + } + + public EmergencyGeneratorController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess device.", type = Ess.class) + public ConfigChannel ess = new ConfigChannel("ess", this); + + @ChannelInfo(title = "Grid-meter", description = "Sets the grid-meter to detect if the system is Off-Grid or On-Grid.", type = Meter.class) + public ConfigChannel meter = new ConfigChannel("meter", this); + + @ChannelInfo(title = "Min-SOC", description = "If the SOC falls under this value and the system is Off-Grid the generator starts.", type = Long.class) + public ConfigChannel minSoc = new ConfigChannel("minSoc", this); + + @ChannelInfo(title = "Max-SOC", description = "If the system is Off-Grid and the generator is running, the generator stops if the SOC level increases over the Max-SOC.", type = Long.class) + public ConfigChannel maxSoc = new ConfigChannel("maxSoc", this); + + @ChannelInfo(title = "Invert-Output", description = "True if the digital output should be inverted.", type = Boolean.class) + public ConfigChannel invertOutput = new ConfigChannel<>("invertOutput", this); + + @ChannelInfo(title = "On-Grid output on", description = "This value indicates if the system is On-Grid to start(true) or stop(false) the generator.", type = Boolean.class, isOptional = true) + public ConfigChannel onGridOutputOn = new ConfigChannel("onGridOutputOn", this) + .defaultValue(false); + + /* + * Fields + */ + private ThingRepository repo = ThingRepository.getInstance(); + private WriteChannel outputChannel; + private boolean generatorOn = false; + private long lastPower = 0l; + private Long cooldownStartTime = null; + + /* + * Methods + */ + @SuppressWarnings("unchecked") + @ChannelInfo(title = "the address of the Digital Output where the generator is connected to.", type = String.class) + public ConfigChannel outputChannelAddress = new ConfigChannel("outputChannelAddress", this) + .addChangeListener((channel, newValue, oldValue) -> { + Optional channelAddress = (Optional) newValue; + if (channelAddress.isPresent()) { + Optional ch = repo.getChannelByAddress(channelAddress.get()); + if (ch.isPresent()) { + outputChannel = (WriteChannel) ch.get(); + } else { + log.error("Channel " + channelAddress.get() + " not found"); + } + } else { + log.error("'outputChannelAddress' is not configured!"); + } + }); + + @Override + public void run() { + try { + // Check if grid is available + if (!meter.value().voltage.valueOptional().isPresent()) { + // no meassurable voltage => Off-Grid + if (ess.value().gridMode.labelOptional().equals(Optional.of(EssNature.OFF_GRID)) && !generatorOn + && ess.value().soc.value() <= minSoc.value()) { + // switch generator on + startGenerator(); + generatorOn = true; + System.out.println("1: storage is empty. Start generator."); + } else if (ess.value().gridMode.labelOptional().equals(Optional.of(EssNature.ON_GRID)) && generatorOn + && ess.value().soc.value() >= maxSoc.value()) { + // switch generator off + if (cooldownStartTime == null) { + cooldownStartTime = System.currentTimeMillis(); + ess.value().setActivePowerL1.pushWrite(0l); + ess.value().setActivePowerL2.pushWrite(0l); + ess.value().setActivePowerL3.pushWrite(0l); + log.info("Start cooldownphase."); + } else if (cooldownStartTime + 1000 * 60 < System.currentTimeMillis()) { + stopGenerator(); + generatorOn = false; + lastPower = 0l; + cooldownStartTime = null; + System.out.println("Storage is full. Stop generator."); + } + } else if (generatorOn) { + startGenerator(); + if (ess.value().gridMode.labelOptional().equals(Optional.of(EssNature.ON_GRID))) { + if (lastPower > -1000) { + lastPower -= 20l; + } + ess.value().setActivePowerL1.pushWrite(lastPower); + ess.value().setActivePowerL2.pushWrite(lastPower); + ess.value().setActivePowerL3.pushWrite(lastPower); + System.out.println("Charge with " + lastPower * 3 + " kW"); + } + System.out.println("3: "); + } else if (!generatorOn) { + stopGenerator(); + lastPower = 0l; + System.out.println("4: "); + } + } else { + // Grid voltage is in the allowed range + if (onGridOutputOn.value()) { + startGenerator(); + } else { + stopGenerator(); + } + } + } catch (InvalidValueException e) { + log.error("Failed to read value!", e); + } catch (WriteChannelException e) { + log.error("Error due write to output [" + outputChannelAddress.valueOptional().orElse("") + "]", e); + } + } + + private void startGenerator() throws WriteChannelException, InvalidValueException { + if (outputChannel.value() != true ^ invertOutput.value()) { + outputChannel.pushWrite(true ^ invertOutput.value()); + } + } + + private void stopGenerator() throws InvalidValueException, WriteChannelException { + if (outputChannel.value() != false ^ invertOutput.value()) { + outputChannel.pushWrite(false ^ invertOutput.value()); + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/evcs/EvcsController.java b/edge/src/io/openems/impl/controller/evcs/EvcsController.java index 77aaa39e19a..52baffabbcc 100644 --- a/edge/src/io/openems/impl/controller/evcs/EvcsController.java +++ b/edge/src/io/openems/impl/controller/evcs/EvcsController.java @@ -3,6 +3,7 @@ import java.util.Optional; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; @@ -26,6 +27,7 @@ public class EvcsController extends Controller { private Optional lastCurrentMilliAmp = Optional.empty(); private int lagCountdown = CONTROL_LAG; private int waitForValueSet = WAIT_FOR_VALUE_SET; + private ThingStateChannels thingState = new ThingStateChannels(this); /* * Constructors @@ -142,4 +144,9 @@ private void setCurrentMilliAmp(int currentMilliAmp) { log.error("Unable to set EVCS current: " + e.getMessage()); } } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } } diff --git a/edge/src/io/openems/impl/controller/feneconprosetup/FeneconProSetupController.java b/edge/src/io/openems/impl/controller/feneconprosetup/FeneconProSetupController.java index f9a48e41ea8..35f6a5d0714 100644 --- a/edge/src/io/openems/impl/controller/feneconprosetup/FeneconProSetupController.java +++ b/edge/src/io/openems/impl/controller/feneconprosetup/FeneconProSetupController.java @@ -1,82 +1,90 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.feneconprosetup; - -import java.util.List; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.device.nature.ess.EssNature; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; -import io.openems.api.exception.WriteChannelException; - -@ThingInfo(title = "Initial setup for FENECON Pro", description = "Sets the correct factory settings for FENECON Pro energy storage systems.") -public class FeneconProSetupController extends Controller { - - /* - * Constructors - */ - public FeneconProSetupController() { - super(); - } - - public FeneconProSetupController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) - public ConfigChannel> esss = new ConfigChannel>("esss", this); - - /* - * Methods - */ - @Override - public void run() { - try { - for (Ess ess : esss.value()) { - if (ess.pcsMode.labelOptional().isPresent() && ess.pcsMode.labelOptional().get().equals("Debug")) { - if (ess.setupMode.labelOptional().isPresent() - && ess.setupMode.labelOptional().get().equals(EssNature.ON)) { - ess.setPcsMode.pushWriteFromLabel("Remote"); - log.info("Set " + ess.id() + " to Remote mode."); - } else { - log.info(ess.id() + " is not in Remote mode. Go to Setting Mode."); - ess.setSetupMode.pushWriteFromLabel(EssNature.ON); - } - } else { - if (ess.setupMode.labelOptional().isPresent() - && ess.setupMode.labelOptional().get().equals(EssNature.ON)) { - ess.setSetupMode.pushWriteFromLabel(EssNature.OFF); - log.info(ess.id() + " Switch setting mode Off"); - } - } - } - } catch (InvalidValueException | WriteChannelException e) { - log.error("Failed to Finish Setup", e); - } - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.feneconprosetup; + +import java.util.List; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.device.nature.ess.EssNature; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.api.exception.WriteChannelException; + +@ThingInfo(title = "Initial setup for FENECON Pro", description = "Sets the correct factory settings for FENECON Pro energy storage systems.") +public class FeneconProSetupController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + + /* + * Constructors + */ + public FeneconProSetupController() { + super(); + } + + public FeneconProSetupController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) + public ConfigChannel> esss = new ConfigChannel>("esss", this); + + /* + * Methods + */ + @Override + public void run() { + try { + for (Ess ess : esss.value()) { + if (ess.pcsMode.labelOptional().isPresent() && ess.pcsMode.labelOptional().get().equals("Debug")) { + if (ess.setupMode.labelOptional().isPresent() + && ess.setupMode.labelOptional().get().equals(EssNature.ON)) { + ess.setPcsMode.pushWriteFromLabel("Remote"); + log.info("Set " + ess.id() + " to Remote mode."); + } else { + log.info(ess.id() + " is not in Remote mode. Go to Setting Mode."); + ess.setSetupMode.pushWriteFromLabel(EssNature.ON); + } + } else { + if (ess.setupMode.labelOptional().isPresent() + && ess.setupMode.labelOptional().get().equals(EssNature.ON)) { + ess.setSetupMode.pushWriteFromLabel(EssNature.OFF); + log.info(ess.id() + " Switch setting mode Off"); + } + } + } + } catch (InvalidValueException | WriteChannelException e) { + log.error("Failed to Finish Setup", e); + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/offGridIndication/OffGridIndicationController.java b/edge/src/io/openems/impl/controller/offGridIndication/OffGridIndicationController.java index b55a0427bba..2e2c474bb90 100644 --- a/edge/src/io/openems/impl/controller/offGridIndication/OffGridIndicationController.java +++ b/edge/src/io/openems/impl/controller/offGridIndication/OffGridIndicationController.java @@ -25,6 +25,7 @@ import io.openems.api.channel.Channel; import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.device.nature.ess.EssNature; import io.openems.api.doc.ChannelInfo; @@ -42,6 +43,7 @@ public class OffGridIndicationController extends Controller { private boolean isProducerDisconnected = false; private long timeProducerDisconnected; private long startTime = System.currentTimeMillis(); + private ThingStateChannels thingState = new ThingStateChannels(this); private enum State { OFFGRID, ONGRID, SWITCHTOOFFGRID, SWITCHTOONGRID, UNKNOWN @@ -111,7 +113,7 @@ public void run() { currentState = State.SWITCHTOONGRID; } } - break; + break; case SWITCHTOOFFGRID: if (isOff()) { if (!isProducerDisconnected) { @@ -151,7 +153,7 @@ public void run() { } } } - break; + break; } } catch (InvalidValueException e) { @@ -170,4 +172,9 @@ private boolean isOff() throws InvalidValueException { return offGridOutputChannel.value() == false; } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/controller/onGridIndication/OnGridIndicationController.java b/edge/src/io/openems/impl/controller/onGridIndication/OnGridIndicationController.java index fa667d8e44a..8460ea7ecc9 100644 --- a/edge/src/io/openems/impl/controller/onGridIndication/OnGridIndicationController.java +++ b/edge/src/io/openems/impl/controller/onGridIndication/OnGridIndicationController.java @@ -25,6 +25,7 @@ import io.openems.api.channel.Channel; import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.device.nature.ess.EssNature; import io.openems.api.doc.ChannelInfo; @@ -42,6 +43,7 @@ public class OnGridIndicationController extends Controller { private boolean isProducerDisconnected = false; private long timeProducerDisconnected; private long startTime = System.currentTimeMillis(); + private ThingStateChannels thingState = new ThingStateChannels(this); private enum State { OFFGRID, ONGRID, SWITCHTOOFFGRID, SWITCHTOONGRID, UNKNOWN @@ -113,7 +115,7 @@ public void run() { currentState = State.SWITCHTOONGRID; } } - break; + break; case SWITCHTOOFFGRID: if (isOff()) { currentState = State.OFFGRID; @@ -157,7 +159,7 @@ public void run() { } } } - break; + break; } } catch (InvalidValueException e) { @@ -176,4 +178,9 @@ private boolean isOnGrid() throws InvalidValueException { return onGridOutputChannel.value() == true; } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/controller/riedmann/RiedmannController.java b/edge/src/io/openems/impl/controller/riedmann/RiedmannController.java index bd82ddcad55..784008cc4d4 100644 --- a/edge/src/io/openems/impl/controller/riedmann/RiedmannController.java +++ b/edge/src/io/openems/impl/controller/riedmann/RiedmannController.java @@ -5,6 +5,7 @@ import io.openems.api.channel.Channel; import io.openems.api.channel.ChannelChangeListener; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.device.nature.ess.EssNature; import io.openems.api.doc.ChannelInfo; @@ -16,6 +17,7 @@ @ThingInfo(title = "Sps parameter Controller") public class RiedmannController extends Controller implements ChannelChangeListener { + private ThingStateChannels thingState = new ThingStateChannels(this); /* * Config-Channel */ @@ -251,4 +253,9 @@ public void channelChanged(Channel channel, Optional newValue, Optional ol updateWaterLevelBorehole3On = true; } } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } } diff --git a/edge/src/io/openems/impl/controller/riedmann/SystemStopController.java b/edge/src/io/openems/impl/controller/riedmann/SystemStopController.java index e76fdf0e8a7..32a9b65203a 100644 --- a/edge/src/io/openems/impl/controller/riedmann/SystemStopController.java +++ b/edge/src/io/openems/impl/controller/riedmann/SystemStopController.java @@ -3,6 +3,7 @@ import java.util.Optional; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.device.nature.ess.EssNature; import io.openems.api.doc.ChannelInfo; @@ -13,6 +14,7 @@ @ThingInfo(title = "SystemStopController") public class SystemStopController extends Controller { + private ThingStateChannels thingState = new ThingStateChannels(this); /* * Config-Channel */ @@ -67,4 +69,9 @@ public void run() { } } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/controller/supplybusswitch/SupplyBusSwitchController.java b/edge/src/io/openems/impl/controller/supplybusswitch/SupplyBusSwitchController.java index 1e69424381f..edad337ce3a 100644 --- a/edge/src/io/openems/impl/controller/supplybusswitch/SupplyBusSwitchController.java +++ b/edge/src/io/openems/impl/controller/supplybusswitch/SupplyBusSwitchController.java @@ -32,6 +32,7 @@ import io.openems.api.channel.ChannelChangeListener; import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.device.nature.ess.EssNature; import io.openems.api.doc.ChannelInfo; @@ -46,6 +47,7 @@ @ThingInfo(title = "Supply Bus Switch") public class SupplyBusSwitchController extends Controller implements ChannelChangeListener { + private ThingStateChannels thingState = new ThingStateChannels(this); /* * Constructors */ @@ -211,4 +213,9 @@ private Ess getEss(String essName) throws InvalidValueException { return null; } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/controller/symmetric/avoidtotalcharge/AvoidTotalChargeController.java b/edge/src/io/openems/impl/controller/symmetric/avoidtotalcharge/AvoidTotalChargeController.java index 614138012df..0a7b028e0d9 100644 --- a/edge/src/io/openems/impl/controller/symmetric/avoidtotalcharge/AvoidTotalChargeController.java +++ b/edge/src/io/openems/impl/controller/symmetric/avoidtotalcharge/AvoidTotalChargeController.java @@ -9,6 +9,7 @@ import java.util.Set; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; @@ -18,6 +19,7 @@ @ThingInfo(title = "Avoid total charge of battery. (Symmetric)", description = "Provides control over the battery's maximum state of charge at a specific time of day. For symmetric Ess.") public class AvoidTotalChargeController extends Controller { + private ThingStateChannels thingState = new ThingStateChannels(this); /* * Config */ @@ -155,4 +157,9 @@ public void run() { log.error(e.getMessage(),e); } } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } } diff --git a/edge/src/io/openems/impl/controller/symmetric/avoidtotaldischarge/AvoidTotalDischargeController.java b/edge/src/io/openems/impl/controller/symmetric/avoidtotaldischarge/AvoidTotalDischargeController.java index 0bdc89fa738..609b78fc825 100644 --- a/edge/src/io/openems/impl/controller/symmetric/avoidtotaldischarge/AvoidTotalDischargeController.java +++ b/edge/src/io/openems/impl/controller/symmetric/avoidtotaldischarge/AvoidTotalDischargeController.java @@ -24,6 +24,7 @@ import java.util.Set; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.device.nature.ess.EssNature; import io.openems.api.doc.ChannelInfo; @@ -35,6 +36,7 @@ @ThingInfo(title = "Avoid total discharge of battery (Symmetric)", description = "Makes sure the battery is not going into critically low state of charge. For symmetric Ess.") public class AvoidTotalDischargeController extends Controller { + private ThingStateChannels thingState = new ThingStateChannels(this); /* * Constructors */ @@ -132,4 +134,9 @@ public void run() { log.error("no ess configured"+e.getMessage()); } } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } } diff --git a/edge/src/io/openems/impl/controller/symmetric/avoidtotaldischargesoctimeline/AvoidTotalDischargeSocTimeLineController.java b/edge/src/io/openems/impl/controller/symmetric/avoidtotaldischargesoctimeline/AvoidTotalDischargeSocTimeLineController.java index 2671f86bc9c..1e4a8b614e4 100644 --- a/edge/src/io/openems/impl/controller/symmetric/avoidtotaldischargesoctimeline/AvoidTotalDischargeSocTimeLineController.java +++ b/edge/src/io/openems/impl/controller/symmetric/avoidtotaldischargesoctimeline/AvoidTotalDischargeSocTimeLineController.java @@ -1,163 +1,170 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.symmetric.avoidtotaldischargesoctimeline; - -import java.time.LocalTime; -import java.time.format.DateTimeFormatter; -import java.util.Optional; -import java.util.Set; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import io.openems.api.channel.Channel; -import io.openems.api.channel.ChannelChangeListener; -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; -import io.openems.api.exception.WriteChannelException; -import io.openems.impl.controller.symmetric.avoidtotaldischargesoctimeline.Ess.State; - -@ThingInfo(title = "Avoid total discharge of battery (Symmetric)", description = "Makes sure the battery is not going into critically low state of charge. For symmetric Ess.") -public class AvoidTotalDischargeSocTimeLineController extends Controller implements ChannelChangeListener { - - /* - * Constructors - */ - public AvoidTotalDischargeSocTimeLineController() { - super(); - } - - public AvoidTotalDischargeSocTimeLineController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) - public final ConfigChannel> esss = new ConfigChannel>("esss", this).addChangeListener(this); - - @ChannelInfo(title = "Soc timeline", description = "This option configures an minsoc at a time for an ess. If no minsoc for an ess is configured the controller uses the minsoc of the ess.", type = JsonArray.class) - public final ConfigChannel socTimeline = new ConfigChannel("socTimeline", this) - .addChangeListener(this); - - /* - * Methods - */ - @Override - public void run() { - try { - LocalTime time = LocalTime.now(); - for (Ess ess : esss.value()) { - switch (ess.currentState) { - case CHARGESOC: - if (ess.soc.value() > ess.getMinSoc(time)) { - ess.currentState = State.MINSOC; - } else { - try { - Optional currentMinValue = ess.setActivePower.writeMin(); - if (currentMinValue.isPresent() && currentMinValue.get() < 0) { - // Force Charge with minimum of MaxChargePower/5 - log.info("Force charge. Set ActivePower=Max[" + currentMinValue.get() / 5 + "]"); - ess.setActivePower.pushWriteMax(currentMinValue.get() / 5); - } else { - log.info("Avoid discharge. Set ActivePower=Max[-1000 W]"); - ess.setActivePower.pushWriteMax(-1000L); - } - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - break; - case MINSOC: - if (ess.soc.value() < ess.getChargeSoc(time)) { - ess.currentState = State.CHARGESOC; - } else if (ess.soc.value() >= ess.getMinSoc(time) + 5) { - ess.currentState = State.NORMAL; - } else { - try { - long maxPower = 0; - if (!ess.setActivePower.writeMax().isPresent() - || maxPower < ess.setActivePower.writeMax().get()) { - ess.setActivePower.pushWriteMax(maxPower); - } - } catch (WriteChannelException e) { - log.error(ess.id() + "Failed to set Max allowed power.", e); - } - } - break; - case NORMAL: - if (ess.soc.value() <= ess.getMinSoc(time)) { - ess.currentState = State.MINSOC; - } - break; - } - - } - } catch (InvalidValueException e) { - log.error(e.getMessage()); - } - } - - private Ess getEss(String id) throws InvalidValueException { - for (Ess ess : esss.value()) { - if (ess.id().equals(id)) { - return ess; - } - } - return null; - } - - @Override - public void channelChanged(Channel channel, Optional newValue, Optional oldValue) { - if (channel.equals(esss) || channel.equals(socTimeline)) { - if (esss.valueOptional().isPresent() && socTimeline.valueOptional().isPresent() - && socTimeline.valueOptional().get() instanceof JsonArray) { - JsonArray timeline = socTimeline.valueOptional().get(); - for (JsonElement e : timeline) { - JsonObject obj = e.getAsJsonObject(); - int minSoc = obj.get("minSoc").getAsInt(); - int chargeSoc = obj.get("chargeSoc").getAsInt(); - LocalTime time = LocalTime.parse(obj.get("time").getAsString(), DateTimeFormatter.ISO_LOCAL_TIME); - JsonArray storages = obj.get("esss").getAsJsonArray(); - for (JsonElement storage : storages) { - Ess ess; - try { - ess = getEss(storage.getAsString()); - if (ess != null) { - ess.addTime(time, minSoc, chargeSoc); - } - } catch (InvalidValueException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - } - } - } - } - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.symmetric.avoidtotaldischargesoctimeline; + +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.util.Optional; +import java.util.Set; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import io.openems.api.channel.Channel; +import io.openems.api.channel.ChannelChangeListener; +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.api.exception.WriteChannelException; +import io.openems.impl.controller.symmetric.avoidtotaldischargesoctimeline.Ess.State; + +@ThingInfo(title = "Avoid total discharge of battery (Symmetric)", description = "Makes sure the battery is not going into critically low state of charge. For symmetric Ess.") +public class AvoidTotalDischargeSocTimeLineController extends Controller implements ChannelChangeListener { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public AvoidTotalDischargeSocTimeLineController() { + super(); + } + + public AvoidTotalDischargeSocTimeLineController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) + public final ConfigChannel> esss = new ConfigChannel>("esss", this).addChangeListener(this); + + @ChannelInfo(title = "Soc timeline", description = "This option configures an minsoc at a time for an ess. If no minsoc for an ess is configured the controller uses the minsoc of the ess.", type = JsonArray.class) + public final ConfigChannel socTimeline = new ConfigChannel("socTimeline", this) + .addChangeListener(this); + + /* + * Methods + */ + @Override + public void run() { + try { + LocalTime time = LocalTime.now(); + for (Ess ess : esss.value()) { + switch (ess.currentState) { + case CHARGESOC: + if (ess.soc.value() > ess.getMinSoc(time)) { + ess.currentState = State.MINSOC; + } else { + try { + Optional currentMinValue = ess.setActivePower.writeMin(); + if (currentMinValue.isPresent() && currentMinValue.get() < 0) { + // Force Charge with minimum of MaxChargePower/5 + log.info("Force charge. Set ActivePower=Max[" + currentMinValue.get() / 5 + "]"); + ess.setActivePower.pushWriteMax(currentMinValue.get() / 5); + } else { + log.info("Avoid discharge. Set ActivePower=Max[-1000 W]"); + ess.setActivePower.pushWriteMax(-1000L); + } + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + break; + case MINSOC: + if (ess.soc.value() < ess.getChargeSoc(time)) { + ess.currentState = State.CHARGESOC; + } else if (ess.soc.value() >= ess.getMinSoc(time) + 5) { + ess.currentState = State.NORMAL; + } else { + try { + long maxPower = 0; + if (!ess.setActivePower.writeMax().isPresent() + || maxPower < ess.setActivePower.writeMax().get()) { + ess.setActivePower.pushWriteMax(maxPower); + } + } catch (WriteChannelException e) { + log.error(ess.id() + "Failed to set Max allowed power.", e); + } + } + break; + case NORMAL: + if (ess.soc.value() <= ess.getMinSoc(time)) { + ess.currentState = State.MINSOC; + } + break; + } + + } + } catch (InvalidValueException e) { + log.error(e.getMessage()); + } + } + + private Ess getEss(String id) throws InvalidValueException { + for (Ess ess : esss.value()) { + if (ess.id().equals(id)) { + return ess; + } + } + return null; + } + + @Override + public void channelChanged(Channel channel, Optional newValue, Optional oldValue) { + if (channel.equals(esss) || channel.equals(socTimeline)) { + if (esss.valueOptional().isPresent() && socTimeline.valueOptional().isPresent() + && socTimeline.valueOptional().get() instanceof JsonArray) { + JsonArray timeline = socTimeline.valueOptional().get(); + for (JsonElement e : timeline) { + JsonObject obj = e.getAsJsonObject(); + int minSoc = obj.get("minSoc").getAsInt(); + int chargeSoc = obj.get("chargeSoc").getAsInt(); + LocalTime time = LocalTime.parse(obj.get("time").getAsString(), DateTimeFormatter.ISO_LOCAL_TIME); + JsonArray storages = obj.get("esss").getAsJsonArray(); + for (JsonElement storage : storages) { + Ess ess; + try { + ess = getEss(storage.getAsString()); + if (ess != null) { + ess.addTime(time, minSoc, chargeSoc); + } + } catch (InvalidValueException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + } + } + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/symmetric/balancing/BalancingController.java b/edge/src/io/openems/impl/controller/symmetric/balancing/BalancingController.java index c67333385cd..f42bcecab36 100644 --- a/edge/src/io/openems/impl/controller/symmetric/balancing/BalancingController.java +++ b/edge/src/io/openems/impl/controller/symmetric/balancing/BalancingController.java @@ -26,6 +26,7 @@ import java.util.Optional; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.device.nature.ess.EssNature; import io.openems.api.doc.ChannelInfo; @@ -36,6 +37,7 @@ @ThingInfo(title = "Self-consumption optimization (Symmetric)", description = "Tries to keep the grid meter on zero. For symmetric Ess. Ess-Cluster is supported.") public class BalancingController extends Controller { + private ThingStateChannels thingState = new ThingStateChannels(this); /* * Constructors */ @@ -193,4 +195,9 @@ private List getUseableEss() throws InvalidValueException { return useableEss; } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/controller/symmetric/balancingbandgap/BalancingBandgapController.java b/edge/src/io/openems/impl/controller/symmetric/balancingbandgap/BalancingBandgapController.java index 475b9d5f4de..8c808e381a6 100644 --- a/edge/src/io/openems/impl/controller/symmetric/balancingbandgap/BalancingBandgapController.java +++ b/edge/src/io/openems/impl/controller/symmetric/balancingbandgap/BalancingBandgapController.java @@ -1,117 +1,124 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.symmetric.balancingbandgap; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; - -@ThingInfo(title = "Balancing bandgap (Symmetric)", description = "Tries to keep the grid meter within a bandgap. For symmetric Ess.") -public class BalancingBandgapController extends Controller { - - /* - * Constructors - */ - public BalancingBandgapController() { - super(); - } - - public BalancingBandgapController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class) - public final ConfigChannel ess = new ConfigChannel("ess", this); - - @ChannelInfo(title = "Grid-Meter", description = "Sets the grid meter.", type = Meter.class) - public final ConfigChannel meter = new ConfigChannel("meter", this); - - @ChannelInfo(title = "Min-ActivePower", description = "Low boundary of active power bandgap.", type = Integer.class) - public final ConfigChannel minActivePower = new ConfigChannel<>("minActivePower", this); - - @ChannelInfo(title = "Max-ActivePower", description = "High boundary of active power bandgap.", type = Integer.class) - public final ConfigChannel maxActivePower = new ConfigChannel<>("maxActivePower", this); - - @ChannelInfo(title = "Min-ReactivePower", description = "Low boundary of reactive power bandgap.", type = Integer.class) - public final ConfigChannel minReactivePower = new ConfigChannel<>("minReactivePower", this); - - @ChannelInfo(title = "Max-ReactivePower", description = "High boundary of reactive power bandgap.", type = Integer.class) - public final ConfigChannel maxReactivePower = new ConfigChannel<>("maxReactivePower", this); - - @ChannelInfo(title = "Enable ActivePower", description = "Indicates if active power bandgap is enabled.", type = Boolean.class, defaultValue = "true") - public final ConfigChannel activePowerActivated = new ConfigChannel("activePowerActivated", this); - - @ChannelInfo(title = "Enable ReactivePower", description = "Indicates if reactive power bandgap is enabled.", type = Boolean.class, defaultValue = "true") - public final ConfigChannel reactivePowerActivated = new ConfigChannel("reactivePowerActivated", - this); - - /* - * Methods - */ - @Override - public void run() { - try { - Ess ess = this.ess.value(); - Meter meter = this.meter.value(); - // Calculate required sum values - long calculatedPower = meter.activePower.value() + ess.activePower.value(); - long calculatedReactivePower = meter.reactivePower.value() + ess.reactivePower.value(); - if (calculatedPower >= maxActivePower.value()) { - calculatedPower -= maxActivePower.value(); - } else if (calculatedPower <= minActivePower.value()) { - calculatedPower -= minActivePower.value(); - } else { - calculatedPower = 0; - } - if (calculatedReactivePower >= maxReactivePower.value()) { - calculatedReactivePower -= maxReactivePower.value(); - } else if (calculatedReactivePower <= minReactivePower.value()) { - calculatedReactivePower -= minReactivePower.value(); - } else { - calculatedReactivePower = 0; - } - if (reactivePowerActivated.value()) { - ess.power.setReactivePower(calculatedReactivePower); - } - if (activePowerActivated.value()) { - ess.power.setActivePower(calculatedPower); - } - ess.power.writePower(); - // write info message to log - String message = ess.id(); - if (activePowerActivated.value()) { - message = message + " Set ActivePower [" + ess.power.getActivePower() + "]"; - } - if (reactivePowerActivated.value()) { - message = message + " Set ReactivePower [" + ess.power.getReactivePower() + "]"; - } - log.info(message); - } catch (InvalidValueException e) { - log.error(e.getMessage()); - } - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.symmetric.balancingbandgap; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; + +@ThingInfo(title = "Balancing bandgap (Symmetric)", description = "Tries to keep the grid meter within a bandgap. For symmetric Ess.") +public class BalancingBandgapController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public BalancingBandgapController() { + super(); + } + + public BalancingBandgapController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class) + public final ConfigChannel ess = new ConfigChannel("ess", this); + + @ChannelInfo(title = "Grid-Meter", description = "Sets the grid meter.", type = Meter.class) + public final ConfigChannel meter = new ConfigChannel("meter", this); + + @ChannelInfo(title = "Min-ActivePower", description = "Low boundary of active power bandgap.", type = Integer.class) + public final ConfigChannel minActivePower = new ConfigChannel<>("minActivePower", this); + + @ChannelInfo(title = "Max-ActivePower", description = "High boundary of active power bandgap.", type = Integer.class) + public final ConfigChannel maxActivePower = new ConfigChannel<>("maxActivePower", this); + + @ChannelInfo(title = "Min-ReactivePower", description = "Low boundary of reactive power bandgap.", type = Integer.class) + public final ConfigChannel minReactivePower = new ConfigChannel<>("minReactivePower", this); + + @ChannelInfo(title = "Max-ReactivePower", description = "High boundary of reactive power bandgap.", type = Integer.class) + public final ConfigChannel maxReactivePower = new ConfigChannel<>("maxReactivePower", this); + + @ChannelInfo(title = "Enable ActivePower", description = "Indicates if active power bandgap is enabled.", type = Boolean.class, defaultValue = "true") + public final ConfigChannel activePowerActivated = new ConfigChannel("activePowerActivated", this); + + @ChannelInfo(title = "Enable ReactivePower", description = "Indicates if reactive power bandgap is enabled.", type = Boolean.class, defaultValue = "true") + public final ConfigChannel reactivePowerActivated = new ConfigChannel("reactivePowerActivated", + this); + + /* + * Methods + */ + @Override + public void run() { + try { + Ess ess = this.ess.value(); + Meter meter = this.meter.value(); + // Calculate required sum values + long calculatedPower = meter.activePower.value() + ess.activePower.value(); + long calculatedReactivePower = meter.reactivePower.value() + ess.reactivePower.value(); + if (calculatedPower >= maxActivePower.value()) { + calculatedPower -= maxActivePower.value(); + } else if (calculatedPower <= minActivePower.value()) { + calculatedPower -= minActivePower.value(); + } else { + calculatedPower = 0; + } + if (calculatedReactivePower >= maxReactivePower.value()) { + calculatedReactivePower -= maxReactivePower.value(); + } else if (calculatedReactivePower <= minReactivePower.value()) { + calculatedReactivePower -= minReactivePower.value(); + } else { + calculatedReactivePower = 0; + } + if (reactivePowerActivated.value()) { + ess.power.setReactivePower(calculatedReactivePower); + } + if (activePowerActivated.value()) { + ess.power.setActivePower(calculatedPower); + } + ess.power.writePower(); + // write info message to log + String message = ess.id(); + if (activePowerActivated.value()) { + message = message + " Set ActivePower [" + ess.power.getActivePower() + "]"; + } + if (reactivePowerActivated.value()) { + message = message + " Set ReactivePower [" + ess.power.getReactivePower() + "]"; + } + log.info(message); + } catch (InvalidValueException e) { + log.error(e.getMessage()); + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/symmetric/balancingcosphi/BalancingCosPhiController.java b/edge/src/io/openems/impl/controller/symmetric/balancingcosphi/BalancingCosPhiController.java index 27967cd51d4..4ed0174200f 100644 --- a/edge/src/io/openems/impl/controller/symmetric/balancingcosphi/BalancingCosPhiController.java +++ b/edge/src/io/openems/impl/controller/symmetric/balancingcosphi/BalancingCosPhiController.java @@ -1,73 +1,80 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.symmetric.balancingcosphi; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; - -@ThingInfo(title = "Balancing Cos-Phi (Symmetric)", description = "Tries to keep the grid meter at a given cos-phi. For symmetric Ess.") -public class BalancingCosPhiController extends Controller { - - /* - * Constructors - */ - public BalancingCosPhiController() { - super(); - } - - public BalancingCosPhiController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class) - public ConfigChannel ess = new ConfigChannel("ess", this); - - @ChannelInfo(title = "Grid-Meter", description = "Sets the grid meter.", type = Meter.class) - public ConfigChannel meter = new ConfigChannel("meter", this); - - @ChannelInfo(title = "Cos-Phi", description = "Cos-phi which the grid-meter is trying to hold.", type = Double.class) - public ConfigChannel cosPhi = new ConfigChannel("cosPhi", this); - - /* - * Methods - */ - @Override - public void run() { - try { - double cosPhi = this.cosPhi.value(); - double phi = Math.acos(cosPhi); - long q = (long) ((meter.value().activePower.value() * Math.tan(phi)) - meter.value().reactivePower.value()) - * -1; - q += ess.value().reactivePower.value(); - ess.value().power.setReactivePower(q); - ess.value().power.writePower(); - log.info(ess.id() + " Set ReactivePower [" + ess.value().power.getReactivePower() + "]"); - } catch (InvalidValueException e) { - log.error("Failed to read value.", e); - } - } -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.symmetric.balancingcosphi; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; + +@ThingInfo(title = "Balancing Cos-Phi (Symmetric)", description = "Tries to keep the grid meter at a given cos-phi. For symmetric Ess.") +public class BalancingCosPhiController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public BalancingCosPhiController() { + super(); + } + + public BalancingCosPhiController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class) + public ConfigChannel ess = new ConfigChannel("ess", this); + + @ChannelInfo(title = "Grid-Meter", description = "Sets the grid meter.", type = Meter.class) + public ConfigChannel meter = new ConfigChannel("meter", this); + + @ChannelInfo(title = "Cos-Phi", description = "Cos-phi which the grid-meter is trying to hold.", type = Double.class) + public ConfigChannel cosPhi = new ConfigChannel("cosPhi", this); + + /* + * Methods + */ + @Override + public void run() { + try { + double cosPhi = this.cosPhi.value(); + double phi = Math.acos(cosPhi); + long q = (long) ((meter.value().activePower.value() * Math.tan(phi)) - meter.value().reactivePower.value()) + * -1; + q += ess.value().reactivePower.value(); + ess.value().power.setReactivePower(q); + ess.value().power.writePower(); + log.info(ess.id() + " Set ReactivePower [" + ess.value().power.getReactivePower() + "]"); + } catch (InvalidValueException e) { + log.error("Failed to read value.", e); + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } +} diff --git a/edge/src/io/openems/impl/controller/symmetric/balancingcurrent/BalancingCurrentController.java b/edge/src/io/openems/impl/controller/symmetric/balancingcurrent/BalancingCurrentController.java index 39030e630ee..11b56bd014a 100644 --- a/edge/src/io/openems/impl/controller/symmetric/balancingcurrent/BalancingCurrentController.java +++ b/edge/src/io/openems/impl/controller/symmetric/balancingcurrent/BalancingCurrentController.java @@ -1,91 +1,98 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.symmetric.balancingcurrent; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; - -@ThingInfo(title = "Balancing current (Symmetric)", description = "Tries to keep the grid meter at a given current. For symmetric Ess.") -public class BalancingCurrentController extends Controller { - - /* - * Constructors - */ - public BalancingCurrentController() { - super(); - } - - public BalancingCurrentController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class) - public final ConfigChannel ess = new ConfigChannel("ess", this); - - @ChannelInfo(title = "Grid-Meter", description = "Sets the grid meter.", type = Meter.class) - public final ConfigChannel meter = new ConfigChannel("meter", this); - - @ChannelInfo(title = "Current offset", description = "The current to hold on the grid-meter.", type = Meter.class) - public final ConfigChannel currentOffset = new ConfigChannel<>("CurrentOffset", this); - - /* - * Methods - */ - @Override - public void run() { - try { - Ess ess = this.ess.value(); - // Calculate required sum values - long power = calculatePower() + ess.activePower.value(); - ess.power.setActivePower(power); - ess.power.writePower(); - log.info(ess.id() + " Set ActivePower [" + ess.power.getActivePower() + "]"); - } catch (InvalidValueException e) { - log.error(e.getMessage()); - } - } - - private long calculatePower() throws InvalidValueException { - long currentL1 = meter.value().currentL1.value(); - if (meter.value().activePowerL1.value() < 0) { - currentL1 *= -1; - } - long powerL1 = ((currentL1 - currentOffset.value() / 3) / 1000) * (meter.value().voltageL1.value() / 1000); - long currentL2 = meter.value().currentL2.value(); - if (meter.value().activePowerL2.value() < 0) { - currentL2 *= -1; - } - long powerL2 = ((currentL2 - currentOffset.value() / 3) / 1000) * (meter.value().voltageL2.value() / 1000); - long currentL3 = meter.value().currentL3.value(); - if (meter.value().activePowerL3.value() < 0) { - currentL3 *= -1; - } - long powerL3 = ((currentL3 - currentOffset.value() / 3) / 1000) * (meter.value().voltageL3.value() / 1000); - return powerL1 + powerL2 + powerL3; - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.symmetric.balancingcurrent; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; + +@ThingInfo(title = "Balancing current (Symmetric)", description = "Tries to keep the grid meter at a given current. For symmetric Ess.") +public class BalancingCurrentController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public BalancingCurrentController() { + super(); + } + + public BalancingCurrentController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class) + public final ConfigChannel ess = new ConfigChannel("ess", this); + + @ChannelInfo(title = "Grid-Meter", description = "Sets the grid meter.", type = Meter.class) + public final ConfigChannel meter = new ConfigChannel("meter", this); + + @ChannelInfo(title = "Current offset", description = "The current to hold on the grid-meter.", type = Meter.class) + public final ConfigChannel currentOffset = new ConfigChannel<>("CurrentOffset", this); + + /* + * Methods + */ + @Override + public void run() { + try { + Ess ess = this.ess.value(); + // Calculate required sum values + long power = calculatePower() + ess.activePower.value(); + ess.power.setActivePower(power); + ess.power.writePower(); + log.info(ess.id() + " Set ActivePower [" + ess.power.getActivePower() + "]"); + } catch (InvalidValueException e) { + log.error(e.getMessage()); + } + } + + private long calculatePower() throws InvalidValueException { + long currentL1 = meter.value().currentL1.value(); + if (meter.value().activePowerL1.value() < 0) { + currentL1 *= -1; + } + long powerL1 = ((currentL1 - currentOffset.value() / 3) / 1000) * (meter.value().voltageL1.value() / 1000); + long currentL2 = meter.value().currentL2.value(); + if (meter.value().activePowerL2.value() < 0) { + currentL2 *= -1; + } + long powerL2 = ((currentL2 - currentOffset.value() / 3) / 1000) * (meter.value().voltageL2.value() / 1000); + long currentL3 = meter.value().currentL3.value(); + if (meter.value().activePowerL3.value() < 0) { + currentL3 *= -1; + } + long powerL3 = ((currentL3 - currentOffset.value() / 3) / 1000) * (meter.value().voltageL3.value() / 1000); + return powerL1 + powerL2 + powerL3; + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/symmetric/balancingoffset/BalancingOffsetController.java b/edge/src/io/openems/impl/controller/symmetric/balancingoffset/BalancingOffsetController.java index bdbe77a7857..632495427b1 100644 --- a/edge/src/io/openems/impl/controller/symmetric/balancingoffset/BalancingOffsetController.java +++ b/edge/src/io/openems/impl/controller/symmetric/balancingoffset/BalancingOffsetController.java @@ -25,6 +25,7 @@ import io.openems.api.channel.Channel; import io.openems.api.channel.ChannelChangeListener; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; @@ -37,6 +38,7 @@ @ThingInfo(title = "Balancing offset (Symmetric)", description = "Tries to keep the grid meter within an offset. For symmetric Ess.") public class BalancingOffsetController extends Controller { + private ThingStateChannels thingState = new ThingStateChannels(this); /* * Constructors */ @@ -111,9 +113,9 @@ public void run() { Ess ess = this.ess.value(); // Calculate required sum values long calculatedPower = meter.value().activePower.value() + ess.activePower.value() - - activePowerOffset.value(); + - activePowerOffset.value(); long calculatedReactivePower = meter.value().reactivePower.value() + ess.reactivePower.value() - - reactivePowerOffset.value(); + - reactivePowerOffset.value(); if (reactivePowerActivated.value()) { ess.power.setReactivePower(calculatedReactivePower); } @@ -135,4 +137,9 @@ public void run() { } } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/controller/symmetric/balancingsurplus/BalancingSurplusController.java b/edge/src/io/openems/impl/controller/symmetric/balancingsurplus/BalancingSurplusController.java index 58bd5ec0e92..c34f3849558 100644 --- a/edge/src/io/openems/impl/controller/symmetric/balancingsurplus/BalancingSurplusController.java +++ b/edge/src/io/openems/impl/controller/symmetric/balancingsurplus/BalancingSurplusController.java @@ -1,124 +1,131 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.symmetric.balancingsurplus; - -import java.util.Set; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; -import io.openems.core.utilities.AvgFiFoQueue; - -@ThingInfo(title = "Self-consumption optimization with surplus feed-in (Symmetric)", description = "Tries to keep the grid meter on zero. For symmetric Ess. If ess is over the surplusMinSoc, the ess discharges with the power of the chargers. ") -public class BalancingSurplusController extends Controller { - - /* - * Constructors - */ - public BalancingSurplusController() { - super(); - } - - public BalancingSurplusController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess device.", type = Ess.class) - public final ConfigChannel ess = new ConfigChannel("ess", this); - - @ChannelInfo(title = "Charger", description = "Sets the Chargers connected to the ess.", type = Charger.class, isArray = true) - public final ConfigChannel> chargers = new ConfigChannel>("chargers", this); - - @ChannelInfo(title = "Surplus min soc", description = "The required Soc to start surplus feed-in.", type = Long.class) - public final ConfigChannel surplusMinSoc = new ConfigChannel("surplusMinSoc", this); - - @ChannelInfo(title = "Grid-Meter", description = "Sets the grid meter.", type = Meter.class) - public final ConfigChannel meter = new ConfigChannel("meter", this); - - private AvgFiFoQueue meterActivePower = new AvgFiFoQueue(3, 1.5); - private AvgFiFoQueue essActivePower = new AvgFiFoQueue(3, 1.5); - - private long surplus = 0L; - private boolean surplusOn = false; - - /* - * Methods - */ - - @Override - public void run() { - try { - Ess ess = this.ess.value(); - meterActivePower.add(meter.value().activePower.value()); - essActivePower.add((ess.activePower.value() - surplus)); - // Calculate required sum values - long calculatedPower = meterActivePower.avg() + essActivePower.avg(); - surplus = getSurplusPower(); - // in case the storage has surplus it isn't allowed to charge the storage ac - if (calculatedPower < 0 && surplus > 0) { - calculatedPower = 0; - } - if (getPvVoltage() < 200000 || surplus < 0) { - surplus = 0l; - } - calculatedPower += surplus; - ess.power.setActivePower(calculatedPower); - ess.power.writePower(); - } catch (InvalidValueException e) { - log.error(e.getMessage()); - } - } - - private long getSurplusPower() throws InvalidValueException { - long power = 0l; - if (ess.value().soc.value() >= surplusMinSoc.value() + 2) { - surplusOn = true; - } else if (ess.value().soc.value() < surplusMinSoc.value()) { - surplusOn = false; - } - if (surplusOn) { - for (Charger c : chargers.value()) { - power += c.power.value(); - } - long multiplier = ess.value().soc.value() - surplusMinSoc.value() - 2; - if (multiplier > 0) { - power += ess.value().nominalPower.value() * 0.25 / (100 - surplusMinSoc.value() - 2) * multiplier; - } - } - return power; - } - - private long getPvVoltage() throws InvalidValueException { - long voltage = 0; - for (Charger c : chargers.value()) { - if (c.inputVoltage.value() > voltage) { - voltage = c.inputVoltage.value(); - } - } - return voltage; - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.symmetric.balancingsurplus; + +import java.util.Set; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.core.utilities.AvgFiFoQueue; + +@ThingInfo(title = "Self-consumption optimization with surplus feed-in (Symmetric)", description = "Tries to keep the grid meter on zero. For symmetric Ess. If ess is over the surplusMinSoc, the ess discharges with the power of the chargers. ") +public class BalancingSurplusController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public BalancingSurplusController() { + super(); + } + + public BalancingSurplusController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess device.", type = Ess.class) + public final ConfigChannel ess = new ConfigChannel("ess", this); + + @ChannelInfo(title = "Charger", description = "Sets the Chargers connected to the ess.", type = Charger.class, isArray = true) + public final ConfigChannel> chargers = new ConfigChannel>("chargers", this); + + @ChannelInfo(title = "Surplus min soc", description = "The required Soc to start surplus feed-in.", type = Long.class) + public final ConfigChannel surplusMinSoc = new ConfigChannel("surplusMinSoc", this); + + @ChannelInfo(title = "Grid-Meter", description = "Sets the grid meter.", type = Meter.class) + public final ConfigChannel meter = new ConfigChannel("meter", this); + + private AvgFiFoQueue meterActivePower = new AvgFiFoQueue(3, 1.5); + private AvgFiFoQueue essActivePower = new AvgFiFoQueue(3, 1.5); + + private long surplus = 0L; + private boolean surplusOn = false; + + /* + * Methods + */ + + @Override + public void run() { + try { + Ess ess = this.ess.value(); + meterActivePower.add(meter.value().activePower.value()); + essActivePower.add((ess.activePower.value() - surplus)); + // Calculate required sum values + long calculatedPower = meterActivePower.avg() + essActivePower.avg(); + surplus = getSurplusPower(); + // in case the storage has surplus it isn't allowed to charge the storage ac + if (calculatedPower < 0 && surplus > 0) { + calculatedPower = 0; + } + if (getPvVoltage() < 200000 || surplus < 0) { + surplus = 0l; + } + calculatedPower += surplus; + ess.power.setActivePower(calculatedPower); + ess.power.writePower(); + } catch (InvalidValueException e) { + log.error(e.getMessage()); + } + } + + private long getSurplusPower() throws InvalidValueException { + long power = 0l; + if (ess.value().soc.value() >= surplusMinSoc.value() + 2) { + surplusOn = true; + } else if (ess.value().soc.value() < surplusMinSoc.value()) { + surplusOn = false; + } + if (surplusOn) { + for (Charger c : chargers.value()) { + power += c.power.value(); + } + long multiplier = ess.value().soc.value() - surplusMinSoc.value() - 2; + if (multiplier > 0) { + power += ess.value().nominalPower.value() * 0.25 / (100 - surplusMinSoc.value() - 2) * multiplier; + } + } + return power; + } + + private long getPvVoltage() throws InvalidValueException { + long voltage = 0; + for (Charger c : chargers.value()) { + if (c.inputVoltage.value() > voltage) { + voltage = c.inputVoltage.value(); + } + } + return voltage; + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/symmetric/capacitytest/CapacityTestController.java b/edge/src/io/openems/impl/controller/symmetric/capacitytest/CapacityTestController.java index 466d6a4563e..dd33456bd9d 100644 --- a/edge/src/io/openems/impl/controller/symmetric/capacitytest/CapacityTestController.java +++ b/edge/src/io/openems/impl/controller/symmetric/capacitytest/CapacityTestController.java @@ -1,149 +1,156 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.symmetric.capacitytest; - -import java.io.FileWriter; -import java.io.IOException; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.List; -import java.util.Optional; - -import io.openems.api.channel.Channel; -import io.openems.api.channel.ChannelUpdateListener; -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.device.nature.ess.EssNature; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; -import io.openems.api.exception.WriteChannelException; - -@ThingInfo(title = "Battery capacity test (Symmetric)", description = "Executes a capacity test. For symmetric Ess.") -public class CapacityTestController extends Controller { - - /* - * Constructors - */ - public CapacityTestController() { - super(); - initialize(); - } - - public CapacityTestController(String thingId) { - super(thingId); - initialize(); - } - - /* - * Config - */ - @ChannelInfo(title = "Power", description = "Discharge power of Ess.", type = Integer.class, defaultValue = "750") - public ConfigChannel power = new ConfigChannel("power", this); - - @ChannelInfo(title = "Sleep", description = "Time to sleep after empty ess before start capacityTest.", type = Integer.class, defaultValue = "750") - public ConfigChannel sleep = new ConfigChannel("sleep", this); - - @ChannelInfo(title = "Log-File", description = "Path to save the logfile.", type = String.class) - public ConfigChannel logPath = new ConfigChannel("logPath", this); - - @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) - public ConfigChannel> esss = new ConfigChannel>("esss", this); - - private Long start = null; - - /* - * Fields - */ - private FileWriter fw; - - /* - * Methods - */ - private void initialize() { - logPath.addUpdateListener(new ChannelUpdateListener() { - - @Override - public void channelUpdated(Channel channel, Optional newValue) { - try { - if (fw != null) { - fw.close(); - } - fw = new FileWriter(logPath.value()); - fw.write("time;activePower;soc\n"); - } catch (IOException e) { - log.error(e.getMessage()); - } catch (InvalidValueException e) { - log.error(e.getMessage()); - } - - } - }); - } - - @Override - public void run() { - if (start == null) { - start = System.currentTimeMillis(); - } - if (start != null && start + 5000 <= System.currentTimeMillis()) { - try { - for (Ess ess : esss.value()) { - ess.setWorkState.pushWriteFromLabel(EssNature.START); - if (ess.empty) { - if (ess.timeEmpty + sleep.value() <= System.currentTimeMillis()) { - // Capacitytest - if (ess.full) { - // fully discharge ess - ess.setActivePower.pushWrite((long) power.value()); - } else { - // fully charge ess - ess.setActivePower.pushWrite((long) power.value() * -1); - if (ess.allowedCharge.value() >= -100l - && ess.systemState.labelOptional().equals(Optional.of(EssNature.START))) { - ess.full = true; - } - } - fw.append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) - + ";" + ess.activePower.value() + ";" + ess.soc.value() + "\n"); - fw.flush(); - } - } else { - // prepare for capacityTest - // Empty ess - ess.setActivePower.pushWrite(ess.allowedDischarge.value()); - if (ess.soc.value() <= ess.minSoc.value()) { - ess.empty = true; - ess.timeEmpty = System.currentTimeMillis(); - } - } - } - } catch (InvalidValueException e) { - log.error(e.getMessage()); - } catch (WriteChannelException e) { - log.error(e.getMessage()); - } catch (IOException e) { - log.error(e.getMessage()); - } - } - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.symmetric.capacitytest; + +import java.io.FileWriter; +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Optional; + +import io.openems.api.channel.Channel; +import io.openems.api.channel.ChannelUpdateListener; +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.device.nature.ess.EssNature; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.api.exception.WriteChannelException; + +@ThingInfo(title = "Battery capacity test (Symmetric)", description = "Executes a capacity test. For symmetric Ess.") +public class CapacityTestController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public CapacityTestController() { + super(); + initialize(); + } + + public CapacityTestController(String thingId) { + super(thingId); + initialize(); + } + + /* + * Config + */ + @ChannelInfo(title = "Power", description = "Discharge power of Ess.", type = Integer.class, defaultValue = "750") + public ConfigChannel power = new ConfigChannel("power", this); + + @ChannelInfo(title = "Sleep", description = "Time to sleep after empty ess before start capacityTest.", type = Integer.class, defaultValue = "750") + public ConfigChannel sleep = new ConfigChannel("sleep", this); + + @ChannelInfo(title = "Log-File", description = "Path to save the logfile.", type = String.class) + public ConfigChannel logPath = new ConfigChannel("logPath", this); + + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) + public ConfigChannel> esss = new ConfigChannel>("esss", this); + + private Long start = null; + + /* + * Fields + */ + private FileWriter fw; + + /* + * Methods + */ + private void initialize() { + logPath.addUpdateListener(new ChannelUpdateListener() { + + @Override + public void channelUpdated(Channel channel, Optional newValue) { + try { + if (fw != null) { + fw.close(); + } + fw = new FileWriter(logPath.value()); + fw.write("time;activePower;soc\n"); + } catch (IOException e) { + log.error(e.getMessage()); + } catch (InvalidValueException e) { + log.error(e.getMessage()); + } + + } + }); + } + + @Override + public void run() { + if (start == null) { + start = System.currentTimeMillis(); + } + if (start != null && start + 5000 <= System.currentTimeMillis()) { + try { + for (Ess ess : esss.value()) { + ess.setWorkState.pushWriteFromLabel(EssNature.START); + if (ess.empty) { + if (ess.timeEmpty + sleep.value() <= System.currentTimeMillis()) { + // Capacitytest + if (ess.full) { + // fully discharge ess + ess.setActivePower.pushWrite((long) power.value()); + } else { + // fully charge ess + ess.setActivePower.pushWrite((long) power.value() * -1); + if (ess.allowedCharge.value() >= -100l + && ess.systemState.labelOptional().equals(Optional.of(EssNature.START))) { + ess.full = true; + } + } + fw.append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + + ";" + ess.activePower.value() + ";" + ess.soc.value() + "\n"); + fw.flush(); + } + } else { + // prepare for capacityTest + // Empty ess + ess.setActivePower.pushWrite(ess.allowedDischarge.value()); + if (ess.soc.value() <= ess.minSoc.value()) { + ess.empty = true; + ess.timeEmpty = System.currentTimeMillis(); + } + } + } + } catch (InvalidValueException e) { + log.error(e.getMessage()); + } catch (WriteChannelException e) { + log.error(e.getMessage()); + } catch (IOException e) { + log.error(e.getMessage()); + } + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/symmetric/commercialenergysaver/EnergysavingController.java b/edge/src/io/openems/impl/controller/symmetric/commercialenergysaver/EnergysavingController.java index 4e08618940f..5cae4c3f26a 100644 --- a/edge/src/io/openems/impl/controller/symmetric/commercialenergysaver/EnergysavingController.java +++ b/edge/src/io/openems/impl/controller/symmetric/commercialenergysaver/EnergysavingController.java @@ -1,116 +1,123 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.symmetric.commercialenergysaver; - -import java.util.Optional; -import java.util.Set; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.device.nature.ess.SymmetricEssNature; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; -import io.openems.api.exception.WriteChannelException; - -/** - * @author matthias.rossmann - */ -@ThingInfo(title = "Energy saving (Symmetric)", description = "Sends the Ess to Standby if no power is required for two minutes. Do not use if Off-Grid functionality is required. For symmetric Ess.") -public class EnergysavingController extends Controller { - - /* - * Constructors - */ - public EnergysavingController() { - super(); - } - - public EnergysavingController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) - public final ConfigChannel> esss = new ConfigChannel>("esss", this); - - /* - * Fields - */ - private Long lastTimeValueWritten = 0L; - - /* - * Methods - */ - @Override - public void run() { - try { - for (Ess ess : esss.value()) { - try { - Optional systemState = ess.systemState.labelOptional(); - if (systemState.isPresent()) { - if ((ess.setActivePower.peekWrite().isPresent() && ess.setActivePower.peekWrite().get() != 0) - || (ess.setReactivePower.peekWrite().isPresent() - && ess.setReactivePower.peekWrite().get() != 0)) { - if (!systemState.get().equals(SymmetricEssNature.START)) { - // Current system state is not START - if (ess.setWorkState.peekWriteLabel().orElse(SymmetricEssNature.START) - .equals(SymmetricEssNature.START)) { - // SetWorkState was not set to anything different than START before -> START the - // system - log.info("ESS [" + ess.id() + "] was stopped. Starting..."); - ess.setWorkState.pushWriteFromLabel(SymmetricEssNature.START); - } - } - lastTimeValueWritten = System.currentTimeMillis(); - } else { - /* - * go to Standby if no values were written since two minutes - */ - if (lastTimeValueWritten + 2 * 60 * 1000 < System.currentTimeMillis()) { - if (!systemState.isPresent() || (!systemState.get().equals(SymmetricEssNature.STANDBY) - && !systemState.get().equals("PV-Charge"))) { - // System state was not yet STANDBY or PV-Charge - if (ess.setWorkState.peekWriteLabel().orElse(SymmetricEssNature.STANDBY) - .equals(SymmetricEssNature.STANDBY)) { - // SetWorkState was not set to anything different than STANDBY before -> put the - // system - // in STANDBY - log.info("ESS [" + ess.id() - + "] had no written value since two minutes. Standby..."); - ess.setWorkState.pushWriteFromLabel(SymmetricEssNature.STANDBY); - } - } - } - } - } - } catch (WriteChannelException e) { - log.error("", e); - } - } - } catch (InvalidValueException e) { - log.error("", e); - } - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.symmetric.commercialenergysaver; + +import java.util.Optional; +import java.util.Set; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.device.nature.ess.SymmetricEssNature; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.api.exception.WriteChannelException; + +/** + * @author matthias.rossmann + */ +@ThingInfo(title = "Energy saving (Symmetric)", description = "Sends the Ess to Standby if no power is required for two minutes. Do not use if Off-Grid functionality is required. For symmetric Ess.") +public class EnergysavingController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public EnergysavingController() { + super(); + } + + public EnergysavingController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) + public final ConfigChannel> esss = new ConfigChannel>("esss", this); + + /* + * Fields + */ + private Long lastTimeValueWritten = 0L; + + /* + * Methods + */ + @Override + public void run() { + try { + for (Ess ess : esss.value()) { + try { + Optional systemState = ess.systemState.labelOptional(); + if (systemState.isPresent()) { + if ((ess.setActivePower.peekWrite().isPresent() && ess.setActivePower.peekWrite().get() != 0) + || (ess.setReactivePower.peekWrite().isPresent() + && ess.setReactivePower.peekWrite().get() != 0)) { + if (!systemState.get().equals(SymmetricEssNature.START)) { + // Current system state is not START + if (ess.setWorkState.peekWriteLabel().orElse(SymmetricEssNature.START) + .equals(SymmetricEssNature.START)) { + // SetWorkState was not set to anything different than START before -> START the + // system + log.info("ESS [" + ess.id() + "] was stopped. Starting..."); + ess.setWorkState.pushWriteFromLabel(SymmetricEssNature.START); + } + } + lastTimeValueWritten = System.currentTimeMillis(); + } else { + /* + * go to Standby if no values were written since two minutes + */ + if (lastTimeValueWritten + 2 * 60 * 1000 < System.currentTimeMillis()) { + if (!systemState.isPresent() || (!systemState.get().equals(SymmetricEssNature.STANDBY) + && !systemState.get().equals("PV-Charge"))) { + // System state was not yet STANDBY or PV-Charge + if (ess.setWorkState.peekWriteLabel().orElse(SymmetricEssNature.STANDBY) + .equals(SymmetricEssNature.STANDBY)) { + // SetWorkState was not set to anything different than STANDBY before -> put the + // system + // in STANDBY + log.info("ESS [" + ess.id() + + "] had no written value since two minutes. Standby..."); + ess.setWorkState.pushWriteFromLabel(SymmetricEssNature.STANDBY); + } + } + } + } + } + } catch (WriteChannelException e) { + log.error("", e); + } + } + } catch (InvalidValueException e) { + log.error("", e); + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/symmetric/commercialworkstate/AlwaysOnController.java b/edge/src/io/openems/impl/controller/symmetric/commercialworkstate/AlwaysOnController.java index c9b5b31bd32..f1c77aed2ff 100644 --- a/edge/src/io/openems/impl/controller/symmetric/commercialworkstate/AlwaysOnController.java +++ b/edge/src/io/openems/impl/controller/symmetric/commercialworkstate/AlwaysOnController.java @@ -1,73 +1,80 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.symmetric.commercialworkstate; - -import java.util.Set; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.device.nature.ess.EssNature; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; -import io.openems.api.exception.WriteChannelException; - -/** - * @author matthias.rossmann - */ -@ThingInfo(title = "Keep always running (Symmetric)", description = "Tries to keep the Ess always running. Use if Off-Grid functionality is required. For symmetric Ess.") -public class AlwaysOnController extends Controller { - - /* - * Constructors - */ - public AlwaysOnController() { - super(); - } - - public AlwaysOnController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) - public final ConfigChannel> esss = new ConfigChannel>("esss", this); - - /* - * Methods - */ - @Override - public void run() { - try { - for (Ess ess : esss.value()) { - try { - ess.setWorkState.pushWriteFromLabel(EssNature.START); - } catch (WriteChannelException e) { - log.error("", e); - } - } - } catch (InvalidValueException e) { - log.error("No Storage Found!", e); - } - } -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.symmetric.commercialworkstate; + +import java.util.Set; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.device.nature.ess.EssNature; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.api.exception.WriteChannelException; + +/** + * @author matthias.rossmann + */ +@ThingInfo(title = "Keep always running (Symmetric)", description = "Tries to keep the Ess always running. Use if Off-Grid functionality is required. For symmetric Ess.") +public class AlwaysOnController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public AlwaysOnController() { + super(); + } + + public AlwaysOnController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) + public final ConfigChannel> esss = new ConfigChannel>("esss", this); + + /* + * Methods + */ + @Override + public void run() { + try { + for (Ess ess : esss.value()) { + try { + ess.setWorkState.pushWriteFromLabel(EssNature.START); + } catch (WriteChannelException e) { + log.error("", e); + } + } + } catch (InvalidValueException e) { + log.error("No Storage Found!", e); + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } +} diff --git a/edge/src/io/openems/impl/controller/symmetric/cosphi/CosPhiController.java b/edge/src/io/openems/impl/controller/symmetric/cosphi/CosPhiController.java index d5689ee6296..766f9f5e810 100644 --- a/edge/src/io/openems/impl/controller/symmetric/cosphi/CosPhiController.java +++ b/edge/src/io/openems/impl/controller/symmetric/cosphi/CosPhiController.java @@ -1,72 +1,79 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.symmetric.cosphi; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; -import io.openems.core.utilities.ControllerUtils; - -@ThingInfo(title = "Ess Cos-Phi (Symmetric)", description = "Keeps the Ess at a given cos-phi. For symmetric Ess.") -public class CosPhiController extends Controller { - - /* - * Constructors - */ - public CosPhiController() { - super(); - } - - public CosPhiController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class) - public ConfigChannel ess = new ConfigChannel("ess", this); - - @ChannelInfo(title = "Cos-Phi", description = "The cos-phi to hold on the storage.", type = Double.class) - public ConfigChannel cosPhi = new ConfigChannel("cosPhi", this); - - /* - * Methods - */ - @Override - public void run() { - try { - if (ess.value().setActivePower.peekWrite().isPresent()) { - ess.value().power.setReactivePower(ControllerUtils - .calculateReactivePower(ess.value().setActivePower.peekWrite().get(), cosPhi.value())); - ess.value().power.writePower(); - log.info("Set ReactivePower [" + ess.value().power.getReactivePower() + "]"); - } else { - log.error(ess.id() + " no ActivePower is Set."); - } - } catch (InvalidValueException e) { - log.error("No ess found.", e); - } - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.symmetric.cosphi; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.core.utilities.ControllerUtils; + +@ThingInfo(title = "Ess Cos-Phi (Symmetric)", description = "Keeps the Ess at a given cos-phi. For symmetric Ess.") +public class CosPhiController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public CosPhiController() { + super(); + } + + public CosPhiController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class) + public ConfigChannel ess = new ConfigChannel("ess", this); + + @ChannelInfo(title = "Cos-Phi", description = "The cos-phi to hold on the storage.", type = Double.class) + public ConfigChannel cosPhi = new ConfigChannel("cosPhi", this); + + /* + * Methods + */ + @Override + public void run() { + try { + if (ess.value().setActivePower.peekWrite().isPresent()) { + ess.value().power.setReactivePower(ControllerUtils + .calculateReactivePower(ess.value().setActivePower.peekWrite().get(), cosPhi.value())); + ess.value().power.writePower(); + log.info("Set ReactivePower [" + ess.value().power.getReactivePower() + "]"); + } else { + log.error(ess.id() + " no ActivePower is Set."); + } + } catch (InvalidValueException e) { + log.error("No ess found.", e); + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/symmetric/cosphicharacteristic/CosPhiCharacteristicController.java b/edge/src/io/openems/impl/controller/symmetric/cosphicharacteristic/CosPhiCharacteristicController.java index da7d3f8fae9..140dac28c67 100644 --- a/edge/src/io/openems/impl/controller/symmetric/cosphicharacteristic/CosPhiCharacteristicController.java +++ b/edge/src/io/openems/impl/controller/symmetric/cosphicharacteristic/CosPhiCharacteristicController.java @@ -1,97 +1,104 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.symmetric.cosphicharacteristic; - -import java.util.ArrayList; -import java.util.List; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; -import io.openems.core.utilities.ControllerUtils; -import io.openems.core.utilities.Point; - -@ThingInfo(title = "Cos-Phi Characteristics (Symmetric)") -public class CosPhiCharacteristicController extends Controller { - - /* - * Constructors - */ - public CosPhiCharacteristicController() { - super(); - } - - public CosPhiCharacteristicController(String id) { - super(id); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess device.", type = Ess.class) - public ConfigChannel ess = new ConfigChannel<>("ess", this); - - @ChannelInfo(title = "Cos-Phi characteristic", description = "The points of the characteristic (x = PowerRatio, y = cosPhi).", type = Long[].class, isArray = true) - public ConfigChannel> cosPhiPoints = new ConfigChannel>("cosPhiPoints", this) - .addChangeListener((channel, newValue, oldValue) -> { - List points = new ArrayList<>(); - if (newValue.isPresent()) { - @SuppressWarnings("unchecked") List cosPhiPoints = (List) newValue.get(); - for (Long[] arr : cosPhiPoints) { - points.add(new Point(arr[0], arr[1])); - } - } else { - log.error("found no cosPhiPoints!"); - } - cosPhiCharacteristic = points; - }); - - /* - * Fields - */ - public List cosPhiCharacteristic; - - /* - * Methods - */ - @Override - public void run() { - try { - if (ess.value().setActivePower.peekWrite().isPresent()) { - double pRatio = (double) ess.value().setActivePower.peekWrite().get() - / (double) ess.value().nominalPower.value() * 100; - double cosPhi = ControllerUtils.getValueOfLine(cosPhiCharacteristic, pRatio) / 100; - ess.value().power.setReactivePower( - ControllerUtils.calculateReactivePower(ess.value().setActivePower.peekWrite().get(), cosPhi)); - ess.value().power.writePower(); - log.info("Set reactive power [{}] to get cosPhi [{}]", - new Object[] { ess.value().power.getReactivePower(), cosPhi }); - } else { - log.error(ess.id() + " no ActivePower is Set."); - } - } catch (InvalidValueException e) { - log.error("No ess found.", e); - } - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.symmetric.cosphicharacteristic; + +import java.util.ArrayList; +import java.util.List; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.core.utilities.ControllerUtils; +import io.openems.core.utilities.Point; + +@ThingInfo(title = "Cos-Phi Characteristics (Symmetric)") +public class CosPhiCharacteristicController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public CosPhiCharacteristicController() { + super(); + } + + public CosPhiCharacteristicController(String id) { + super(id); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess device.", type = Ess.class) + public ConfigChannel ess = new ConfigChannel<>("ess", this); + + @ChannelInfo(title = "Cos-Phi characteristic", description = "The points of the characteristic (x = PowerRatio, y = cosPhi).", type = Long[].class, isArray = true) + public ConfigChannel> cosPhiPoints = new ConfigChannel>("cosPhiPoints", this) + .addChangeListener((channel, newValue, oldValue) -> { + List points = new ArrayList<>(); + if (newValue.isPresent()) { + @SuppressWarnings("unchecked") List cosPhiPoints = (List) newValue.get(); + for (Long[] arr : cosPhiPoints) { + points.add(new Point(arr[0], arr[1])); + } + } else { + log.error("found no cosPhiPoints!"); + } + cosPhiCharacteristic = points; + }); + + /* + * Fields + */ + public List cosPhiCharacteristic; + + /* + * Methods + */ + @Override + public void run() { + try { + if (ess.value().setActivePower.peekWrite().isPresent()) { + double pRatio = (double) ess.value().setActivePower.peekWrite().get() + / (double) ess.value().nominalPower.value() * 100; + double cosPhi = ControllerUtils.getValueOfLine(cosPhiCharacteristic, pRatio) / 100; + ess.value().power.setReactivePower( + ControllerUtils.calculateReactivePower(ess.value().setActivePower.peekWrite().get(), cosPhi)); + ess.value().power.writePower(); + log.info("Set reactive power [{}] to get cosPhi [{}]", + new Object[] { ess.value().power.getReactivePower(), cosPhi }); + } else { + log.error(ess.id() + " no ActivePower is Set."); + } + } catch (InvalidValueException e) { + log.error("No ess found.", e); + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/symmetric/fixvalue/FixValueController.java b/edge/src/io/openems/impl/controller/symmetric/fixvalue/FixValueController.java index 0a0a28a5af4..850f3a136e0 100644 --- a/edge/src/io/openems/impl/controller/symmetric/fixvalue/FixValueController.java +++ b/edge/src/io/openems/impl/controller/symmetric/fixvalue/FixValueController.java @@ -23,6 +23,7 @@ import java.util.List; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; @@ -31,6 +32,7 @@ @ThingInfo(title = "Fixed active and reactive power (Symmetric)", description = "Charges or discharges the battery with a predefined, fixed power. For symmetric Ess.") public class FixValueController extends Controller { + private ThingStateChannels thingState = new ThingStateChannels(this); /* * Constructors */ @@ -74,4 +76,9 @@ public void run() { } } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/controller/symmetric/offGridPowerStation/OffGridPowerStationController.java b/edge/src/io/openems/impl/controller/symmetric/offGridPowerStation/OffGridPowerStationController.java index 7db4f53bade..d059ad7b6cb 100644 --- a/edge/src/io/openems/impl/controller/symmetric/offGridPowerStation/OffGridPowerStationController.java +++ b/edge/src/io/openems/impl/controller/symmetric/offGridPowerStation/OffGridPowerStationController.java @@ -1,274 +1,281 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.symmetric.offGridPowerStation; - -import java.util.Optional; - -import io.openems.api.channel.Channel; -import io.openems.api.channel.ConfigChannel; -import io.openems.api.channel.WriteChannel; -import io.openems.api.controller.Controller; -import io.openems.api.device.nature.ess.EssNature; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; -import io.openems.api.exception.WriteChannelException; -import io.openems.core.ThingRepository; - -@ThingInfo(title = "External power station control", description = "Starts an thermal power station in case of off-Grid and empty ess.") -public class OffGridPowerStationController extends Controller { - - /* - * Constructors - */ - public OffGridPowerStationController() { - super(); - } - - public OffGridPowerStationController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess device.", type = Ess.class) - public ConfigChannel ess = new ConfigChannel("ess", this); - - @ChannelInfo(title = "Grid-meter", description = "Sets the grid-meter to detect if the system is Off-Grid or On-Grid.", type = Meter.class) - public ConfigChannel meter = new ConfigChannel("meter", this); - - @ChannelInfo(title = "Min-SOC", description = "If the SOC falls under this value and the system is Off-Grid the generator starts.", type = Long.class) - public ConfigChannel minSoc = new ConfigChannel("minSoc", this); - - @ChannelInfo(title = "Max-SOC", description = "If the system is Off-Grid and the generator is running, the generator stops if the SOC level increases over the Max-SOC.", type = Long.class) - public ConfigChannel maxSoc = new ConfigChannel("maxSoc", this); - - @ChannelInfo(title = "Invert-Output", description = "True if the digital output should be inverted.", type = Boolean.class) - public ConfigChannel invertOutput = new ConfigChannel<>("invertOutput", this); - - @ChannelInfo(title = "On-Grid output on", description = "This value indicates if the system is On-Grid to start(true) or stop(false) the generator.", type = Boolean.class, isOptional = true) - public ConfigChannel onGridOutputOn = new ConfigChannel("onGridOutputOn", this) - .defaultValue(false); - - @ChannelInfo(title = "time to wait before switch output on.", type = Long.class) - public ConfigChannel switchDelay = new ConfigChannel("switchDelay", this).defaultValue(10000L); - - /* - * Fields - */ - private ThingRepository repo = ThingRepository.getInstance(); - private WriteChannel outputChannel; - private long timeOnGrid = 0L; - private long timeOffGrid = 0L; - private long startTime = System.currentTimeMillis(); - private State currentState = State.UNKNOWN; - private OffGridState currentOffGridState = OffGridState.STOP; - - private enum State { - GOONGRID1, GOONGRID2, ONGRID, GOOFFGRID, OFFGRID, UNKNOWN - } - - private enum OffGridState { - STOPGENERATOR, STARTGENERATOR, STOP, RUNNING - } - - /* - * Methods - */ - @SuppressWarnings("unchecked") - @ChannelInfo(title = "the address of the Digital Output where the generator is connected to.", type = String.class) - public ConfigChannel outputChannelAddress = new ConfigChannel("outputChannelAddress", this) - .addChangeListener((channel, newValue, oldValue) -> { - Optional channelAddress = (Optional) newValue; - if (channelAddress.isPresent()) { - Optional ch = repo.getChannelByAddress(channelAddress.get()); - if (ch.isPresent()) { - outputChannel = (WriteChannel) ch.get(); - } else { - log.error("Channel " + channelAddress.get() + " not found"); - } - } else { - log.error("'outputChannelAddress' is not configured!"); - } - }); - - @Override - public void run() { - if (startTime + 1000 * 15 <= System.currentTimeMillis()) { - try { - switch (currentState) { - case GOOFFGRID: - if (isOff()) { - if (timeOffGrid + switchDelay.value() <= System.currentTimeMillis()) { - currentState = State.OFFGRID; - } - } else { - stopGenerator(); - timeOffGrid = System.currentTimeMillis(); - } - break; - case GOONGRID1: - if (isOff()) { - if (timeOnGrid + switchDelay.value() <= System.currentTimeMillis()) { - currentState = State.GOONGRID2; - } - } else { - stopGenerator(); - timeOnGrid = System.currentTimeMillis(); - } - break; - case GOONGRID2: - // check if outputstate is correct according to onGridOutputOn => !(1^1) = 1, !(1^0) = 0, - // !(0^1) = 0, !(0^0) = 1 - if (!(onGridOutputOn.value() ^ isOn())) { - currentState = State.ONGRID; - } else { - if (onGridOutputOn.value()) { - startGenerator(); - } else { - stopGenerator(); - } - } - break; - case ONGRID: - if (meter.value().voltage.valueOptional().isPresent() - || ess.value().gridMode.labelOptional().equals(Optional.of(EssNature.ON_GRID))) { - if (onGridOutputOn.value() ^ isOn()) { - currentState = State.GOONGRID2; - } - } else { - currentState = State.GOOFFGRID; - } - break; - case OFFGRID: - if (meter.value().voltage.valueOptional().isPresent()) { - currentState = State.GOONGRID1; - currentOffGridState = OffGridState.STOP; - } else { - switch (currentOffGridState) { - case RUNNING: - if (!ess.value().soc.valueOptional().isPresent() - || ess.value().soc.value() >= maxSoc.value()) { - currentOffGridState = OffGridState.STOPGENERATOR; - } - break; - case STARTGENERATOR: - if (isOn()) { - currentOffGridState = OffGridState.RUNNING; - } else { - startGenerator(); - } - break; - case STOP: - if (ess.value().soc.valueOptional().isPresent() - && ess.value().soc.value() <= minSoc.value()) { - currentOffGridState = OffGridState.STARTGENERATOR; - } - break; - case STOPGENERATOR: - if (isOff()) { - currentOffGridState = OffGridState.STOP; - } else { - stopGenerator(); - } - break; - } - } - log.info("current Off-Grid State: " + currentOffGridState); - break; - case UNKNOWN: - default: - if (meter.value().voltage.valueOptional().isPresent()) { - currentState = State.GOONGRID2; - } else { - currentState = State.GOOFFGRID; - } - break; - - } - log.info("current State: " + currentState); - // // Check if grid is available - // if (!meter.value().voltage.valueOptional().isPresent()) { - // // no meassurable voltage => Off-Grid - // if (!generatorOn && ess.value().soc.valueOptional().isPresent() - // && ess.value().soc.value() <= minSoc.value()) { - // // switch generator on - // startGenerator(); - // generatorOn = true; - // } else if (generatorOn && (!ess.value().soc.valueOptional().isPresent() - // || ess.value().soc.value() >= maxSoc.value())) { - // // switch generator off - // stopGenerator(); - // generatorOn = false; - // } else if (generatorOn) { - // startGenerator(); - // } else if (!generatorOn) { - // stopGenerator(); - // } - // switchedToOnGrid = false; - // } else { - // // Grid voltage is in the allowed range - // if (switchedToOnGrid) { - // if (timeOnGrid + switchDelay.value() <= System.currentTimeMillis()) { - // if (onGridOutputOn.value()) { - // startGenerator(); - // } else { - // stopGenerator(); - // } - // } - // } else { - // stopGenerator(); - // timeOnGrid = System.currentTimeMillis(); - // switchedToOnGrid = true; - // } - // } - } catch (InvalidValueException e) { - log.error("Failed to read value!", e); - } catch (WriteChannelException e) { - log.error("Error due write to output [" + outputChannelAddress.valueOptional().orElse("") + "]", - e); - } - } - - } - - private void startGenerator() throws WriteChannelException, InvalidValueException { - if (outputChannel.value() != true ^ invertOutput.value()) { - outputChannel.pushWrite(true ^ invertOutput.value()); - } - } - - private void stopGenerator() throws InvalidValueException, WriteChannelException { - if (outputChannel.value() != false ^ invertOutput.value()) { - outputChannel.pushWrite(false ^ invertOutput.value()); - } - } - - private boolean isOff() throws InvalidValueException { - return outputChannel.value() == false ^ invertOutput.value(); - } - - private boolean isOn() throws InvalidValueException { - return outputChannel.value() == true ^ invertOutput.value(); - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.symmetric.offGridPowerStation; + +import java.util.Optional; + +import io.openems.api.channel.Channel; +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.device.nature.ess.EssNature; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.api.exception.WriteChannelException; +import io.openems.core.ThingRepository; + +@ThingInfo(title = "External power station control", description = "Starts an thermal power station in case of off-Grid and empty ess.") +public class OffGridPowerStationController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public OffGridPowerStationController() { + super(); + } + + public OffGridPowerStationController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess device.", type = Ess.class) + public ConfigChannel ess = new ConfigChannel("ess", this); + + @ChannelInfo(title = "Grid-meter", description = "Sets the grid-meter to detect if the system is Off-Grid or On-Grid.", type = Meter.class) + public ConfigChannel meter = new ConfigChannel("meter", this); + + @ChannelInfo(title = "Min-SOC", description = "If the SOC falls under this value and the system is Off-Grid the generator starts.", type = Long.class) + public ConfigChannel minSoc = new ConfigChannel("minSoc", this); + + @ChannelInfo(title = "Max-SOC", description = "If the system is Off-Grid and the generator is running, the generator stops if the SOC level increases over the Max-SOC.", type = Long.class) + public ConfigChannel maxSoc = new ConfigChannel("maxSoc", this); + + @ChannelInfo(title = "Invert-Output", description = "True if the digital output should be inverted.", type = Boolean.class) + public ConfigChannel invertOutput = new ConfigChannel<>("invertOutput", this); + + @ChannelInfo(title = "On-Grid output on", description = "This value indicates if the system is On-Grid to start(true) or stop(false) the generator.", type = Boolean.class, isOptional = true) + public ConfigChannel onGridOutputOn = new ConfigChannel("onGridOutputOn", this) + .defaultValue(false); + + @ChannelInfo(title = "time to wait before switch output on.", type = Long.class) + public ConfigChannel switchDelay = new ConfigChannel("switchDelay", this).defaultValue(10000L); + + /* + * Fields + */ + private ThingRepository repo = ThingRepository.getInstance(); + private WriteChannel outputChannel; + private long timeOnGrid = 0L; + private long timeOffGrid = 0L; + private long startTime = System.currentTimeMillis(); + private State currentState = State.UNKNOWN; + private OffGridState currentOffGridState = OffGridState.STOP; + + private enum State { + GOONGRID1, GOONGRID2, ONGRID, GOOFFGRID, OFFGRID, UNKNOWN + } + + private enum OffGridState { + STOPGENERATOR, STARTGENERATOR, STOP, RUNNING + } + + /* + * Methods + */ + @SuppressWarnings("unchecked") + @ChannelInfo(title = "the address of the Digital Output where the generator is connected to.", type = String.class) + public ConfigChannel outputChannelAddress = new ConfigChannel("outputChannelAddress", this) + .addChangeListener((channel, newValue, oldValue) -> { + Optional channelAddress = (Optional) newValue; + if (channelAddress.isPresent()) { + Optional ch = repo.getChannelByAddress(channelAddress.get()); + if (ch.isPresent()) { + outputChannel = (WriteChannel) ch.get(); + } else { + log.error("Channel " + channelAddress.get() + " not found"); + } + } else { + log.error("'outputChannelAddress' is not configured!"); + } + }); + + @Override + public void run() { + if (startTime + 1000 * 15 <= System.currentTimeMillis()) { + try { + switch (currentState) { + case GOOFFGRID: + if (isOff()) { + if (timeOffGrid + switchDelay.value() <= System.currentTimeMillis()) { + currentState = State.OFFGRID; + } + } else { + stopGenerator(); + timeOffGrid = System.currentTimeMillis(); + } + break; + case GOONGRID1: + if (isOff()) { + if (timeOnGrid + switchDelay.value() <= System.currentTimeMillis()) { + currentState = State.GOONGRID2; + } + } else { + stopGenerator(); + timeOnGrid = System.currentTimeMillis(); + } + break; + case GOONGRID2: + // check if outputstate is correct according to onGridOutputOn => !(1^1) = 1, !(1^0) = 0, + // !(0^1) = 0, !(0^0) = 1 + if (!(onGridOutputOn.value() ^ isOn())) { + currentState = State.ONGRID; + } else { + if (onGridOutputOn.value()) { + startGenerator(); + } else { + stopGenerator(); + } + } + break; + case ONGRID: + if (meter.value().voltage.valueOptional().isPresent() + || ess.value().gridMode.labelOptional().equals(Optional.of(EssNature.ON_GRID))) { + if (onGridOutputOn.value() ^ isOn()) { + currentState = State.GOONGRID2; + } + } else { + currentState = State.GOOFFGRID; + } + break; + case OFFGRID: + if (meter.value().voltage.valueOptional().isPresent()) { + currentState = State.GOONGRID1; + currentOffGridState = OffGridState.STOP; + } else { + switch (currentOffGridState) { + case RUNNING: + if (!ess.value().soc.valueOptional().isPresent() + || ess.value().soc.value() >= maxSoc.value()) { + currentOffGridState = OffGridState.STOPGENERATOR; + } + break; + case STARTGENERATOR: + if (isOn()) { + currentOffGridState = OffGridState.RUNNING; + } else { + startGenerator(); + } + break; + case STOP: + if (ess.value().soc.valueOptional().isPresent() + && ess.value().soc.value() <= minSoc.value()) { + currentOffGridState = OffGridState.STARTGENERATOR; + } + break; + case STOPGENERATOR: + if (isOff()) { + currentOffGridState = OffGridState.STOP; + } else { + stopGenerator(); + } + break; + } + } + log.info("current Off-Grid State: " + currentOffGridState); + break; + case UNKNOWN: + default: + if (meter.value().voltage.valueOptional().isPresent()) { + currentState = State.GOONGRID2; + } else { + currentState = State.GOOFFGRID; + } + break; + + } + log.info("current State: " + currentState); + // // Check if grid is available + // if (!meter.value().voltage.valueOptional().isPresent()) { + // // no meassurable voltage => Off-Grid + // if (!generatorOn && ess.value().soc.valueOptional().isPresent() + // && ess.value().soc.value() <= minSoc.value()) { + // // switch generator on + // startGenerator(); + // generatorOn = true; + // } else if (generatorOn && (!ess.value().soc.valueOptional().isPresent() + // || ess.value().soc.value() >= maxSoc.value())) { + // // switch generator off + // stopGenerator(); + // generatorOn = false; + // } else if (generatorOn) { + // startGenerator(); + // } else if (!generatorOn) { + // stopGenerator(); + // } + // switchedToOnGrid = false; + // } else { + // // Grid voltage is in the allowed range + // if (switchedToOnGrid) { + // if (timeOnGrid + switchDelay.value() <= System.currentTimeMillis()) { + // if (onGridOutputOn.value()) { + // startGenerator(); + // } else { + // stopGenerator(); + // } + // } + // } else { + // stopGenerator(); + // timeOnGrid = System.currentTimeMillis(); + // switchedToOnGrid = true; + // } + // } + } catch (InvalidValueException e) { + log.error("Failed to read value!", e); + } catch (WriteChannelException e) { + log.error("Error due write to output [" + outputChannelAddress.valueOptional().orElse("") + "]", + e); + } + } + + } + + private void startGenerator() throws WriteChannelException, InvalidValueException { + if (outputChannel.value() != true ^ invertOutput.value()) { + outputChannel.pushWrite(true ^ invertOutput.value()); + } + } + + private void stopGenerator() throws InvalidValueException, WriteChannelException { + if (outputChannel.value() != false ^ invertOutput.value()) { + outputChannel.pushWrite(false ^ invertOutput.value()); + } + } + + private boolean isOff() throws InvalidValueException { + return outputChannel.value() == false ^ invertOutput.value(); + } + + private boolean isOn() throws InvalidValueException { + return outputChannel.value() == true ^ invertOutput.value(); + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/symmetric/powerbyfrequency/PowerByFrequencyController.java b/edge/src/io/openems/impl/controller/symmetric/powerbyfrequency/PowerByFrequencyController.java index c9d4959bea1..60d750a9e6a 100644 --- a/edge/src/io/openems/impl/controller/symmetric/powerbyfrequency/PowerByFrequencyController.java +++ b/edge/src/io/openems/impl/controller/symmetric/powerbyfrequency/PowerByFrequencyController.java @@ -1,91 +1,98 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.symmetric.powerbyfrequency; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; - -@ThingInfo(title = "Power by frequency (Symmetric)", description = "Tries to keep the grid meter at a given frequency. For symmetric Ess.") -public class PowerByFrequencyController extends Controller { - - /* - * Constructors - */ - public PowerByFrequencyController() { - super(); - } - - public PowerByFrequencyController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess device.", type = Ess.class) - public final ConfigChannel ess = new ConfigChannel<>("ess", this); - - @ChannelInfo(title = "Meter", description = "The meter for the frequency meassurement.", type = Meter.class) - public final ConfigChannel meter = new ConfigChannel<>("meter", this); - - @ChannelInfo(title = "Low SOC-Limit", description = "The low soc limit. Below this limit the Ess will charge with more power by the same frequency.", type = Integer.class, defaultValue = "30") - public final ConfigChannel lowSocLimit = new ConfigChannel("lowSocLimit", this); - - @ChannelInfo(title = "High SOC-Limit", description = "The upper soc limit. Above this limit the Ess will discharge with more power by the same frequency.", type = Integer.class, defaultValue = "70") - public final ConfigChannel highSocLimit = new ConfigChannel("highSocLimit", this); - - /* - * Methods - */ - @Override - public void run() { - try { - Ess ess = this.ess.value(); - Meter meter = this.meter.value(); - // Calculate required sum values - long activePower = 0L; - if (meter.frequency.value() >= 49990 && meter.frequency.value() <= 50010) { - // charge if SOC isn't in the expected range - if ((ess.soc.value() > highSocLimit.value() && meter.frequency.value() < 50000) - || (ess.soc.value() < lowSocLimit.value() && meter.frequency.value() > 50000)) { - activePower = (long) (ess.maxNominalPower.value() * (300.0 - 0.006 * meter.frequency.value())); - } - } else { - // calculate minimal Power for Frequency - activePower = (long) ((double) ess.maxNominalPower.value() * (250.0 - meter.frequency.value() / 200.0)); - if ((meter.frequency.value() < 50000 && ess.soc.value() > highSocLimit.value()) - || (meter.frequency.value() > 50000 && ess.soc.value() < lowSocLimit.value())) { - // calculate maximal Power for frequency - activePower = (long) (ess.maxNominalPower.value() * (300 - 0.006 * meter.frequency.value())); - } - } - ess.power.setActivePower(activePower); - ess.power.writePower(); - log.info(ess.id() + " Set ActivePower [" + ess.power.getActivePower() + "]"); - } catch (InvalidValueException e) { - log.error(e.getMessage()); - } - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.symmetric.powerbyfrequency; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; + +@ThingInfo(title = "Power by frequency (Symmetric)", description = "Tries to keep the grid meter at a given frequency. For symmetric Ess.") +public class PowerByFrequencyController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public PowerByFrequencyController() { + super(); + } + + public PowerByFrequencyController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess device.", type = Ess.class) + public final ConfigChannel ess = new ConfigChannel<>("ess", this); + + @ChannelInfo(title = "Meter", description = "The meter for the frequency meassurement.", type = Meter.class) + public final ConfigChannel meter = new ConfigChannel<>("meter", this); + + @ChannelInfo(title = "Low SOC-Limit", description = "The low soc limit. Below this limit the Ess will charge with more power by the same frequency.", type = Integer.class, defaultValue = "30") + public final ConfigChannel lowSocLimit = new ConfigChannel("lowSocLimit", this); + + @ChannelInfo(title = "High SOC-Limit", description = "The upper soc limit. Above this limit the Ess will discharge with more power by the same frequency.", type = Integer.class, defaultValue = "70") + public final ConfigChannel highSocLimit = new ConfigChannel("highSocLimit", this); + + /* + * Methods + */ + @Override + public void run() { + try { + Ess ess = this.ess.value(); + Meter meter = this.meter.value(); + // Calculate required sum values + long activePower = 0L; + if (meter.frequency.value() >= 49990 && meter.frequency.value() <= 50010) { + // charge if SOC isn't in the expected range + if ((ess.soc.value() > highSocLimit.value() && meter.frequency.value() < 50000) + || (ess.soc.value() < lowSocLimit.value() && meter.frequency.value() > 50000)) { + activePower = (long) (ess.maxNominalPower.value() * (300.0 - 0.006 * meter.frequency.value())); + } + } else { + // calculate minimal Power for Frequency + activePower = (long) ((double) ess.maxNominalPower.value() * (250.0 - meter.frequency.value() / 200.0)); + if ((meter.frequency.value() < 50000 && ess.soc.value() > highSocLimit.value()) + || (meter.frequency.value() > 50000 && ess.soc.value() < lowSocLimit.value())) { + // calculate maximal Power for frequency + activePower = (long) (ess.maxNominalPower.value() * (300 - 0.006 * meter.frequency.value())); + } + } + ess.power.setActivePower(activePower); + ess.power.writePower(); + log.info(ess.id() + " Set ActivePower [" + ess.power.getActivePower() + "]"); + } catch (InvalidValueException e) { + log.error(e.getMessage()); + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/symmetric/powerlimitation/PowerLimitationController.java b/edge/src/io/openems/impl/controller/symmetric/powerlimitation/PowerLimitationController.java index df36f48ed98..fd300c949d9 100644 --- a/edge/src/io/openems/impl/controller/symmetric/powerlimitation/PowerLimitationController.java +++ b/edge/src/io/openems/impl/controller/symmetric/powerlimitation/PowerLimitationController.java @@ -1,101 +1,108 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.symmetric.powerlimitation; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; -import io.openems.api.exception.WriteChannelException; - -@ThingInfo(title = "Power limitation (Symmetric)", description = "Limits the active and reactive power of the Ess. For symmetric Ess.") -public class PowerLimitationController extends Controller { - - /* - * Constructors - */ - public PowerLimitationController() { - super(); - } - - public PowerLimitationController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class) - public ConfigChannel ess = new ConfigChannel("ess", this); - - @ChannelInfo(title = "Min-Charge ActivePower", description = "The minimum allowed active power for discharge. Value is negative.", type = Long.class) - public ConfigChannel pMin = new ConfigChannel("pMin", this); - - @ChannelInfo(title = "Max-Charge ActivePower", description = "The maximum allowed active power for discharge. Value is positive.", type = Long.class) - public ConfigChannel pMax = new ConfigChannel("pMax", this); - - @ChannelInfo(title = "Min-Charge ReactivePower", description = "The minimum allowed reactive power for discharge. Value is negative.", type = Long.class) - public ConfigChannel qMin = new ConfigChannel("qMin", this); - - @ChannelInfo(title = "Max-Charge ReactivePower", description = "The maximum allowed reactive power for discharge. Value is positive.", type = Long.class) - public ConfigChannel qMax = new ConfigChannel("qMax", this); - - /* - * Methods - */ - @Override - public void run() { - try { - try { - if (pMax.value() < ess.value().setActivePower.writeMax().orElse(Long.MAX_VALUE)) { - ess.value().setActivePower.pushWriteMax(pMax.value()); - } - } catch (WriteChannelException | InvalidValueException e) { - log.error("Failed to write Max P value for [" + ess.value().id + "]: " + e.getMessage()); - } - try { - if (pMin.value() > ess.value().setActivePower.writeMin().orElse(Long.MIN_VALUE)) { - ess.value().setActivePower.pushWriteMin(pMin.value()); - } - } catch (WriteChannelException | InvalidValueException e) { - log.error("Failed to write Min P value for [" + ess.value().id + "]: " + e.getMessage()); - } - try { - if (qMin.value() > ess.value().setReactivePower.writeMin().orElse(Long.MIN_VALUE)) { - ess.value().setReactivePower.pushWriteMin(qMin.value()); - } - } catch (WriteChannelException | InvalidValueException e) { - log.error("Failed to write Min Q value for [" + ess.value().id + "]: " + e.getMessage()); - } - try { - if (qMax.value() < ess.value().setReactivePower.writeMax().orElse(Long.MAX_VALUE)) { - ess.value().setReactivePower.pushWriteMax(qMax.value()); - } - } catch (WriteChannelException | InvalidValueException e) { - log.error("Failed to write Max Q value for [" + ess.value().id + "]: " + e.getMessage()); - } - } catch (InvalidValueException e) { - log.error("No ess found.", e); - } - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.symmetric.powerlimitation; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.api.exception.WriteChannelException; + +@ThingInfo(title = "Power limitation (Symmetric)", description = "Limits the active and reactive power of the Ess. For symmetric Ess.") +public class PowerLimitationController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public PowerLimitationController() { + super(); + } + + public PowerLimitationController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class) + public ConfigChannel ess = new ConfigChannel("ess", this); + + @ChannelInfo(title = "Min-Charge ActivePower", description = "The minimum allowed active power for discharge. Value is negative.", type = Long.class) + public ConfigChannel pMin = new ConfigChannel("pMin", this); + + @ChannelInfo(title = "Max-Charge ActivePower", description = "The maximum allowed active power for discharge. Value is positive.", type = Long.class) + public ConfigChannel pMax = new ConfigChannel("pMax", this); + + @ChannelInfo(title = "Min-Charge ReactivePower", description = "The minimum allowed reactive power for discharge. Value is negative.", type = Long.class) + public ConfigChannel qMin = new ConfigChannel("qMin", this); + + @ChannelInfo(title = "Max-Charge ReactivePower", description = "The maximum allowed reactive power for discharge. Value is positive.", type = Long.class) + public ConfigChannel qMax = new ConfigChannel("qMax", this); + + /* + * Methods + */ + @Override + public void run() { + try { + try { + if (pMax.value() < ess.value().setActivePower.writeMax().orElse(Long.MAX_VALUE)) { + ess.value().setActivePower.pushWriteMax(pMax.value()); + } + } catch (WriteChannelException | InvalidValueException e) { + log.error("Failed to write Max P value for [" + ess.value().id + "]: " + e.getMessage()); + } + try { + if (pMin.value() > ess.value().setActivePower.writeMin().orElse(Long.MIN_VALUE)) { + ess.value().setActivePower.pushWriteMin(pMin.value()); + } + } catch (WriteChannelException | InvalidValueException e) { + log.error("Failed to write Min P value for [" + ess.value().id + "]: " + e.getMessage()); + } + try { + if (qMin.value() > ess.value().setReactivePower.writeMin().orElse(Long.MIN_VALUE)) { + ess.value().setReactivePower.pushWriteMin(qMin.value()); + } + } catch (WriteChannelException | InvalidValueException e) { + log.error("Failed to write Min Q value for [" + ess.value().id + "]: " + e.getMessage()); + } + try { + if (qMax.value() < ess.value().setReactivePower.writeMax().orElse(Long.MAX_VALUE)) { + ess.value().setReactivePower.pushWriteMax(qMax.value()); + } + } catch (WriteChannelException | InvalidValueException e) { + log.error("Failed to write Max Q value for [" + ess.value().id + "]: " + e.getMessage()); + } + } catch (InvalidValueException e) { + log.error("No ess found.", e); + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/symmetric/powerramp/PowerRampController.java b/edge/src/io/openems/impl/controller/symmetric/powerramp/PowerRampController.java index 318cbccb27d..7536fe29723 100644 --- a/edge/src/io/openems/impl/controller/symmetric/powerramp/PowerRampController.java +++ b/edge/src/io/openems/impl/controller/symmetric/powerramp/PowerRampController.java @@ -1,110 +1,111 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.symmetric.powerramp; - -import java.util.List; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.device.nature.ess.EssNature; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; -import io.openems.core.utilities.ControllerUtils; -import io.openems.core.utilities.SymmetricPower; - -@ThingInfo(title = "Power ramp (Symmetric)", description = "Follows a power ramp. For symmetric Ess.") -public class PowerRampController extends Controller { - - /* - * Constructors - */ - public PowerRampController() { - super(); - } - - public PowerRampController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) - public ConfigChannel> esss = new ConfigChannel>("esss", this); - - @ChannelInfo(title = "Max-ActivePower", description = "The limit where the powerRamp stops. (pos/neg)", type = Integer.class) - public ConfigChannel pMax = new ConfigChannel("pMax", this); - - @ChannelInfo(title = "Cos-Phi", description = "The cos-phi to hold.", type = Double.class) - public ConfigChannel cosPhi = new ConfigChannel("cosPhi", this); - - @ChannelInfo(title = "Step", description = "Step to increase power.", type = Integer.class) - public ConfigChannel pStep = new ConfigChannel("pStep", this); - - @ChannelInfo(title = "Step-Wait", description = "Wait till next step in milliseconds.", type = Integer.class) - public ConfigChannel sleep = new ConfigChannel<>("sleep", this); - - /* - * Fields - */ - private long lastPower; - private long lastSet; - - /* - * Methods - */ - @Override - public void run() { - try { - for (Ess ess : esss.value()) { - try { - if (ess.gridMode.labelOptional().isPresent() - && ess.gridMode.labelOptional().get().equals(EssNature.OFF_GRID)) { - lastPower = 0; - } - SymmetricPower power = ess.power; - if (lastSet + sleep.value() < System.currentTimeMillis()) { - if (Math.abs(lastPower + pStep.value()) <= Math.abs(pMax.value())) { - power.setActivePower(lastPower + pStep.value()); - } else { - power.setActivePower(pMax.value()); - } - lastSet = System.currentTimeMillis(); - } else { - power.setActivePower(lastPower); - } - power.setReactivePower( - ControllerUtils.calculateReactivePower(power.getActivePower(), cosPhi.value())); - power.writePower(); - lastPower = power.getActivePower(); - log.info("Set ActivePower [" + power.getActivePower() + "] Set ReactivePower [" - + power.getReactivePower() + "]"); - } catch (InvalidValueException e) { - log.error("Failed to write fixed P/Q value for Ess " + ess.id, e); - } - } - } catch (InvalidValueException e) { - log.error("No ess found.", e); - } - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.symmetric.powerramp; + +import java.util.List; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.device.nature.ess.EssNature; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.core.utilities.SymmetricPower; + +@ThingInfo(title = "Power ramp (Symmetric)", description = "Follows a power ramp. For symmetric Ess.") +public class PowerRampController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public PowerRampController() { + super(); + } + + public PowerRampController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) + public ConfigChannel> esss = new ConfigChannel>("esss", this); + + @ChannelInfo(title = "Max-ActivePower", description = "The limit where the powerRamp stops. (pos/neg)", type = Integer.class) + public ConfigChannel pMax = new ConfigChannel("pMax", this); + + @ChannelInfo(title = "Step", description = "Step to increase power.", type = Integer.class) + public ConfigChannel pStep = new ConfigChannel("pStep", this); + + @ChannelInfo(title = "Step-Wait", description = "Wait till next step in milliseconds.", type = Integer.class) + public ConfigChannel sleep = new ConfigChannel<>("sleep", this); + + /* + * Fields + */ + private long lastPower; + private long lastSet; + + /* + * Methods + */ + @Override + public void run() { + try { + for (Ess ess : esss.value()) { + try { + if (ess.gridMode.labelOptional().isPresent() + && ess.gridMode.labelOptional().get().equals(EssNature.OFF_GRID)) { + lastPower = 0; + } + SymmetricPower power = ess.power; + if (lastSet + sleep.value() < System.currentTimeMillis()) { + if (Math.abs(lastPower + pStep.value()) <= Math.abs(pMax.value())) { + power.setActivePower(lastPower + pStep.value()); + } else { + power.setActivePower(pMax.value()); + } + lastSet = System.currentTimeMillis(); + } else { + power.setActivePower(lastPower); + } + power.writePower(); + lastPower = power.getActivePower(); + log.info("Set ActivePower [" + power.getActivePower() + "] Set ReactivePower [" + + power.getReactivePower() + "]"); + } catch (InvalidValueException e) { + log.error("Failed to write fixed P/Q value for Ess " + ess.id, e); + } + } + } catch (InvalidValueException e) { + log.error("No ess found.", e); + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/symmetric/refuavoidtotaldischarge/AvoidTotalDischargeController.java b/edge/src/io/openems/impl/controller/symmetric/refuavoidtotaldischarge/AvoidTotalDischargeController.java index a5d5f357979..66b48dbbab6 100644 --- a/edge/src/io/openems/impl/controller/symmetric/refuavoidtotaldischarge/AvoidTotalDischargeController.java +++ b/edge/src/io/openems/impl/controller/symmetric/refuavoidtotaldischarge/AvoidTotalDischargeController.java @@ -1,219 +1,226 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.symmetric.refuavoidtotaldischarge; - -import java.util.Optional; - -import io.openems.api.channel.Channel; -import io.openems.api.channel.ChannelChangeListener; -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; -import io.openems.api.exception.WriteChannelException; -import io.openems.core.utilities.hysteresis.Hysteresis; - -@ThingInfo(title = "REFU: Avoid Total Discharge") -public class AvoidTotalDischargeController extends Controller { - - @ChannelInfo(title = "Storage, where total discharge should be avoided. For excample to reserve load for the Off-Grid power supply.", type = Ess.class) - public final ConfigChannel ess = new ConfigChannel("ess", this); - @ChannelInfo(title = "Delay, to allow Power after start", type = Long.class) - public final ConfigChannel powerDelay = new ConfigChannel<>("powerDelay", this); - @ChannelInfo(title = "Step to increase the allowed power after start delay.", type = Long.class) - public final ConfigChannel powerStep = new ConfigChannel<>("powerStep", this); - @ChannelInfo(title = "Soc limit to stop chargePower.", type = Long.class) - public final ConfigChannel maxSoc = new ConfigChannel("maxSoc", this) - .addChangeListener(new ChannelChangeListener() { - - @Override - public void channelChanged(Channel channel, Optional newValue, Optional oldValue) { - if (maxSoc.valueOptional().isPresent() && socHysteresis.valueOptional().isPresent()) { - try { - socMaxHysteresis = new Hysteresis(maxSoc.value() - socHysteresis.value(), maxSoc.value()); - } catch (InvalidValueException e) {} - } - } - }); - @ChannelInfo(title = "Soc hysteresis for max Soc limit.", type = Long.class) - public final ConfigChannel socHysteresis = new ConfigChannel("socHysteresis", this) - .addChangeListener(new ChannelChangeListener() { - - @Override - public void channelChanged(Channel channel, Optional newValue, Optional oldValue) { - if (maxSoc.valueOptional().isPresent() && socHysteresis.valueOptional().isPresent()) { - try { - socMaxHysteresis = new Hysteresis(maxSoc.value() - socHysteresis.value(), maxSoc.value()); - } catch (InvalidValueException e) {} - } - } - }); - private boolean isStart = false; - private long timeStartOccured = System.currentTimeMillis(); - private long lastPower = 0L; - private Hysteresis socMaxHysteresis; - - public AvoidTotalDischargeController() { - super(); - } - - public AvoidTotalDischargeController(String thingId) { - super(thingId); - } - - @Override - public void run() { - try { - Ess ess = this.ess.value(); - - if (ess.systemState.value() == 4) { - if (!isStart) { - timeStartOccured = System.currentTimeMillis(); - isStart = true; - } - } else { - isStart = false; - lastPower = 0L; - } - if (isStart && timeStartOccured + powerDelay.value() <= System.currentTimeMillis()) { - lastPower += powerStep.value(); - if (lastPower > ess.nominalPower.value()) { - lastPower = ess.nominalPower.value(); - } - } - try { - ess.setActivePower.pushWriteMin(lastPower * -1); - } catch (WriteChannelException e) { - // catch out of bounds - } - try { - ess.setActivePower.pushWriteMax(lastPower); - } catch (WriteChannelException e) { - // catch out of bounds - } - try { - ess.setReactivePower.pushWriteMin(lastPower * -1); - } catch (WriteChannelException e) { - // catch out of bounds - } - try { - ess.setReactivePower.pushWriteMax(lastPower); - } catch (WriteChannelException e) { - // catch out of bounds - } - - /* - * Calculate SetActivePower according to MinSoc - */ - - ess.socMinHysteresis.apply(ess.soc.value(), (state, multiplier) -> { - switch (state) { - case ASC: - case DESC: - if (!ess.isChargeSoc) { - try { - long maxPower = 0; - if (!ess.setActivePower.writeMax().isPresent() - || maxPower < ess.setActivePower.writeMax().get()) { - ess.setActivePower.pushWriteMax(maxPower); - } - } catch (WriteChannelException e) { - log.error(ess.id() + "Failed to set Max allowed power.", e); - } - } - break; - case BELOW: - if (!ess.isChargeSoc) { - try { - if (ess.soc.value() < ess.chargeSoc.value()) { - ess.isChargeSoc = true; - } - } catch (Exception e) { - log.error(e.getMessage()); - } - } - break; - case ABOVE: - ess.isChargeSoc = false; - default: - break; - } - if (ess.isChargeSoc) { - try { - Optional currentMinValue = ess.setActivePower.writeMin(); - if (currentMinValue.isPresent() && currentMinValue.get() < 0) { - // Force Charge with minimum of MaxChargePower/5 - log.info("Force charge. Set ActivePower=Max[" + currentMinValue.get() / 5 + "]"); - ess.setActivePower.pushWriteMax(currentMinValue.get() / 5); - } else { - log.info("Avoid discharge. Set ActivePower=Max[-1000 W]"); - ess.setActivePower.pushWriteMax(-1000L); - } - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - }); - - if (socMaxHysteresis != null) { - socMaxHysteresis.apply(ess.soc.value(), (state, multiplier) -> { - switch (state) { - case ABOVE: - try { - ess.setActivePower.pushWriteMin(0L); - } catch (WriteChannelException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - break; - case ASC: - try { - ess.setActivePower.pushWriteMin((long) (ess.allowedCharge.value() * multiplier)); - } catch (WriteChannelException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (InvalidValueException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - break; - case BELOW: - break; - case DESC: - try { - ess.setActivePower.pushWriteMin(0L); - } catch (WriteChannelException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - break; - default: - break; - } - }); - } - } catch (InvalidValueException e) { - log.error(e.getMessage()); - } - } -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.symmetric.refuavoidtotaldischarge; + +import java.util.Optional; + +import io.openems.api.channel.Channel; +import io.openems.api.channel.ChannelChangeListener; +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.api.exception.WriteChannelException; +import io.openems.core.utilities.hysteresis.Hysteresis; + +@ThingInfo(title = "REFU: Avoid Total Discharge") +public class AvoidTotalDischargeController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + @ChannelInfo(title = "Storage, where total discharge should be avoided. For excample to reserve load for the Off-Grid power supply.", type = Ess.class) + public final ConfigChannel ess = new ConfigChannel("ess", this); + @ChannelInfo(title = "Delay, to allow Power after start", type = Long.class) + public final ConfigChannel powerDelay = new ConfigChannel<>("powerDelay", this); + @ChannelInfo(title = "Step to increase the allowed power after start delay.", type = Long.class) + public final ConfigChannel powerStep = new ConfigChannel<>("powerStep", this); + @ChannelInfo(title = "Soc limit to stop chargePower.", type = Long.class) + public final ConfigChannel maxSoc = new ConfigChannel("maxSoc", this) + .addChangeListener(new ChannelChangeListener() { + + @Override + public void channelChanged(Channel channel, Optional newValue, Optional oldValue) { + if (maxSoc.valueOptional().isPresent() && socHysteresis.valueOptional().isPresent()) { + try { + socMaxHysteresis = new Hysteresis(maxSoc.value() - socHysteresis.value(), maxSoc.value()); + } catch (InvalidValueException e) {} + } + } + }); + @ChannelInfo(title = "Soc hysteresis for max Soc limit.", type = Long.class) + public final ConfigChannel socHysteresis = new ConfigChannel("socHysteresis", this) + .addChangeListener(new ChannelChangeListener() { + + @Override + public void channelChanged(Channel channel, Optional newValue, Optional oldValue) { + if (maxSoc.valueOptional().isPresent() && socHysteresis.valueOptional().isPresent()) { + try { + socMaxHysteresis = new Hysteresis(maxSoc.value() - socHysteresis.value(), maxSoc.value()); + } catch (InvalidValueException e) {} + } + } + }); + private boolean isStart = false; + private long timeStartOccured = System.currentTimeMillis(); + private long lastPower = 0L; + private Hysteresis socMaxHysteresis; + + public AvoidTotalDischargeController() { + super(); + } + + public AvoidTotalDischargeController(String thingId) { + super(thingId); + } + + @Override + public void run() { + try { + Ess ess = this.ess.value(); + + if (ess.systemState.value() == 4) { + if (!isStart) { + timeStartOccured = System.currentTimeMillis(); + isStart = true; + } + } else { + isStart = false; + lastPower = 0L; + } + if (isStart && timeStartOccured + powerDelay.value() <= System.currentTimeMillis()) { + lastPower += powerStep.value(); + if (lastPower > ess.nominalPower.value()) { + lastPower = ess.nominalPower.value(); + } + } + try { + ess.setActivePower.pushWriteMin(lastPower * -1); + } catch (WriteChannelException e) { + // catch out of bounds + } + try { + ess.setActivePower.pushWriteMax(lastPower); + } catch (WriteChannelException e) { + // catch out of bounds + } + try { + ess.setReactivePower.pushWriteMin(lastPower * -1); + } catch (WriteChannelException e) { + // catch out of bounds + } + try { + ess.setReactivePower.pushWriteMax(lastPower); + } catch (WriteChannelException e) { + // catch out of bounds + } + + /* + * Calculate SetActivePower according to MinSoc + */ + + ess.socMinHysteresis.apply(ess.soc.value(), (state, multiplier) -> { + switch (state) { + case ASC: + case DESC: + if (!ess.isChargeSoc) { + try { + long maxPower = 0; + if (!ess.setActivePower.writeMax().isPresent() + || maxPower < ess.setActivePower.writeMax().get()) { + ess.setActivePower.pushWriteMax(maxPower); + } + } catch (WriteChannelException e) { + log.error(ess.id() + "Failed to set Max allowed power.", e); + } + } + break; + case BELOW: + if (!ess.isChargeSoc) { + try { + if (ess.soc.value() < ess.chargeSoc.value()) { + ess.isChargeSoc = true; + } + } catch (Exception e) { + log.error(e.getMessage()); + } + } + break; + case ABOVE: + ess.isChargeSoc = false; + default: + break; + } + if (ess.isChargeSoc) { + try { + Optional currentMinValue = ess.setActivePower.writeMin(); + if (currentMinValue.isPresent() && currentMinValue.get() < 0) { + // Force Charge with minimum of MaxChargePower/5 + log.info("Force charge. Set ActivePower=Max[" + currentMinValue.get() / 5 + "]"); + ess.setActivePower.pushWriteMax(currentMinValue.get() / 5); + } else { + log.info("Avoid discharge. Set ActivePower=Max[-1000 W]"); + ess.setActivePower.pushWriteMax(-1000L); + } + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + }); + + if (socMaxHysteresis != null) { + socMaxHysteresis.apply(ess.soc.value(), (state, multiplier) -> { + switch (state) { + case ABOVE: + try { + ess.setActivePower.pushWriteMin(0L); + } catch (WriteChannelException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + break; + case ASC: + try { + ess.setActivePower.pushWriteMin((long) (ess.allowedCharge.value() * multiplier)); + } catch (WriteChannelException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvalidValueException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + break; + case BELOW: + break; + case DESC: + try { + ess.setActivePower.pushWriteMin(0L); + } catch (WriteChannelException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + break; + default: + break; + } + }); + } + } catch (InvalidValueException e) { + log.error(e.getMessage()); + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } +} diff --git a/edge/src/io/openems/impl/controller/symmetric/refuworkstate/WorkStateController.java b/edge/src/io/openems/impl/controller/symmetric/refuworkstate/WorkStateController.java index 2a712b2b7af..2a9715ebb43 100644 --- a/edge/src/io/openems/impl/controller/symmetric/refuworkstate/WorkStateController.java +++ b/edge/src/io/openems/impl/controller/symmetric/refuworkstate/WorkStateController.java @@ -24,6 +24,7 @@ import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.DebugChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.device.nature.ess.EssNature; import io.openems.api.doc.ChannelInfo; @@ -37,6 +38,7 @@ @ThingInfo(title = "REFU Workstate (Symmetric)", description = "Sends the Ess to Standby if no power is required. Do not use if Off-Grid functionality is required. For symmetric Ess.") public class WorkStateController extends Controller { + private ThingStateChannels thingState = new ThingStateChannels(this); /* * Constructors */ @@ -213,4 +215,9 @@ public void run() { } } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/controller/symmetric/timelinecharge/TimelineChargeController.java b/edge/src/io/openems/impl/controller/symmetric/timelinecharge/TimelineChargeController.java index 034b2523a99..ff50b6225e5 100644 --- a/edge/src/io/openems/impl/controller/symmetric/timelinecharge/TimelineChargeController.java +++ b/edge/src/io/openems/impl/controller/symmetric/timelinecharge/TimelineChargeController.java @@ -35,6 +35,7 @@ import com.google.gson.JsonObject; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.device.nature.ess.EssNature; import io.openems.api.doc.ChannelInfo; @@ -51,6 +52,7 @@ @ThingInfo(title = "Timeline charge (Symmetric)") public class TimelineChargeController extends Controller { + private ThingStateChannels thingState = new ThingStateChannels(this); /* * Constructors */ @@ -419,4 +421,9 @@ public int getSoc() { } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/controller/symmetric/voltagecharacteristic/VoltageCharacteristicController.java b/edge/src/io/openems/impl/controller/symmetric/voltagecharacteristic/VoltageCharacteristicController.java index 42df2c157dd..131bf0e270a 100644 --- a/edge/src/io/openems/impl/controller/symmetric/voltagecharacteristic/VoltageCharacteristicController.java +++ b/edge/src/io/openems/impl/controller/symmetric/voltagecharacteristic/VoltageCharacteristicController.java @@ -1,143 +1,150 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.symmetric.voltagecharacteristic; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import io.openems.api.channel.Channel; -import io.openems.api.channel.ChannelChangeListener; -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; -import io.openems.core.utilities.ControllerUtils; -import io.openems.core.utilities.Point; -import io.openems.core.utilities.SymmetricPower; - -@ThingInfo(title = "Voltage characteristics (Symmetric)") -public class VoltageCharacteristicController extends Controller { - - /* - * Constructors - */ - public VoltageCharacteristicController() { - super(); - initialize(); - } - - public VoltageCharacteristicController(String thingId) { - super(thingId); - initialize(); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class) - public final ConfigChannel ess = new ConfigChannel("ess", this); - - @ChannelInfo(title = "Meter", description = "The meter to measure the Voltage.", type = Meter.class) - public final ConfigChannel meter = new ConfigChannel("meter", this); - - @ChannelInfo(title = "Nominal voltage", description = "The nominal voltage of the grid.", type = Integer.class) - public final ConfigChannel uNenn = new ConfigChannel<>("UNenn", this); - - @ChannelInfo(title = "ActivePower characteristics", description = "Characteristic points for active power.", type = Long[].class, isArray = true) - public final ConfigChannel> pByUCharacteristicPoints = new ConfigChannel<>("pByUCharacteristicPoints", - this); - - @ChannelInfo(title = "ReactivePower characteristics", description = "Characteristic points for reactive power.", type = Long[].class, isArray = true) - public final ConfigChannel> qByUCharacteristicPoints = new ConfigChannel<>("qByUCharacteristicPoints", - this); - - @ChannelInfo(title = "Enable ActivePower", description = "Indicates if active power characteristic is enabled.", type = Boolean.class, defaultValue = "true") - public final ConfigChannel activePowerActivated = new ConfigChannel<>("activePowerActivated", this); - - @ChannelInfo(title = "Enable ReactivePower", description = "Indicates if reactive power characteristic is enabled.", type = Boolean.class, defaultValue = "true") - public final ConfigChannel reactivePowerActivated = new ConfigChannel<>("reactivePowerActivated", this); - - /* - * Fields - */ - private List pCharacteristic; - private List qCharacteristic; - - /* - * Methods - */ - private void initialize() { - pByUCharacteristicPoints.addChangeListener(new ChannelChangeListener() { - - @Override - public void channelChanged(Channel channel, Optional newValue, Optional oldValue) { - try { - List points = new ArrayList<>(); - for (Long[] arr : pByUCharacteristicPoints.value()) { - points.add(new Point(arr[0], arr[1])); - } - pCharacteristic = points; - } catch (InvalidValueException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - }); - qByUCharacteristicPoints.addChangeListener(new ChannelChangeListener() { - - @Override - public void channelChanged(Channel channel, Optional newValue, Optional oldValue) { - try { - List points = new ArrayList<>(); - for (Long[] arr : qByUCharacteristicPoints.value()) { - points.add(new Point(arr[0], arr[1])); - } - qCharacteristic = points; - } catch (InvalidValueException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - }); - } - - @Override - public void run() { - try { - SymmetricPower power = ess.value().power; - double uRatio = (double) meter.value().voltage.value() / (double) uNenn.value() * 100.0; - long nominalActivePower = ess.value().maxNominalPower.value(); - long nominalReactivePower = ess.value().maxNominalPower.value(); - power.setActivePower( - (long) (nominalActivePower / 100.0 * ControllerUtils.getValueOfLine(pCharacteristic, uRatio))); - power.setReactivePower( - (long) (nominalReactivePower / 100.0 * ControllerUtils.getValueOfLine(qCharacteristic, uRatio))); - power.writePower(); - log.info(ess.id() + " Set ActivePower [" + power.getActivePower() + "], ReactivePower [" - + power.getReactivePower() + "]"); - } catch (InvalidValueException e) { - log.error("Failed to read Value.", e); - } - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.symmetric.voltagecharacteristic; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import io.openems.api.channel.Channel; +import io.openems.api.channel.ChannelChangeListener; +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.core.utilities.ControllerUtils; +import io.openems.core.utilities.Point; +import io.openems.core.utilities.SymmetricPower; + +@ThingInfo(title = "Voltage characteristics (Symmetric)") +public class VoltageCharacteristicController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Constructors + */ + public VoltageCharacteristicController() { + super(); + initialize(); + } + + public VoltageCharacteristicController(String thingId) { + super(thingId); + initialize(); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class) + public final ConfigChannel ess = new ConfigChannel("ess", this); + + @ChannelInfo(title = "Meter", description = "The meter to measure the Voltage.", type = Meter.class) + public final ConfigChannel meter = new ConfigChannel("meter", this); + + @ChannelInfo(title = "Nominal voltage", description = "The nominal voltage of the grid.", type = Integer.class) + public final ConfigChannel uNenn = new ConfigChannel<>("UNenn", this); + + @ChannelInfo(title = "ActivePower characteristics", description = "Characteristic points for active power.", type = Long[].class, isArray = true) + public final ConfigChannel> pByUCharacteristicPoints = new ConfigChannel<>("pByUCharacteristicPoints", + this); + + @ChannelInfo(title = "ReactivePower characteristics", description = "Characteristic points for reactive power.", type = Long[].class, isArray = true) + public final ConfigChannel> qByUCharacteristicPoints = new ConfigChannel<>("qByUCharacteristicPoints", + this); + + @ChannelInfo(title = "Enable ActivePower", description = "Indicates if active power characteristic is enabled.", type = Boolean.class, defaultValue = "true") + public final ConfigChannel activePowerActivated = new ConfigChannel<>("activePowerActivated", this); + + @ChannelInfo(title = "Enable ReactivePower", description = "Indicates if reactive power characteristic is enabled.", type = Boolean.class, defaultValue = "true") + public final ConfigChannel reactivePowerActivated = new ConfigChannel<>("reactivePowerActivated", this); + + /* + * Fields + */ + private List pCharacteristic; + private List qCharacteristic; + + /* + * Methods + */ + private void initialize() { + pByUCharacteristicPoints.addChangeListener(new ChannelChangeListener() { + + @Override + public void channelChanged(Channel channel, Optional newValue, Optional oldValue) { + try { + List points = new ArrayList<>(); + for (Long[] arr : pByUCharacteristicPoints.value()) { + points.add(new Point(arr[0], arr[1])); + } + pCharacteristic = points; + } catch (InvalidValueException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + }); + qByUCharacteristicPoints.addChangeListener(new ChannelChangeListener() { + + @Override + public void channelChanged(Channel channel, Optional newValue, Optional oldValue) { + try { + List points = new ArrayList<>(); + for (Long[] arr : qByUCharacteristicPoints.value()) { + points.add(new Point(arr[0], arr[1])); + } + qCharacteristic = points; + } catch (InvalidValueException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + }); + } + + @Override + public void run() { + try { + SymmetricPower power = ess.value().power; + double uRatio = (double) meter.value().voltage.value() / (double) uNenn.value() * 100.0; + long nominalActivePower = ess.value().maxNominalPower.value(); + long nominalReactivePower = ess.value().maxNominalPower.value(); + power.setActivePower( + (long) (nominalActivePower / 100.0 * ControllerUtils.getValueOfLine(pCharacteristic, uRatio))); + power.setReactivePower( + (long) (nominalReactivePower / 100.0 * ControllerUtils.getValueOfLine(qCharacteristic, uRatio))); + power.writePower(); + log.info(ess.id() + " Set ActivePower [" + power.getActivePower() + "], ReactivePower [" + + power.getReactivePower() + "]"); + } catch (InvalidValueException e) { + log.error("Failed to read Value.", e); + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/systemstate/alwayson/AlwaysOnController.java b/edge/src/io/openems/impl/controller/systemstate/alwayson/AlwaysOnController.java new file mode 100644 index 00000000000..03f289edf9d --- /dev/null +++ b/edge/src/io/openems/impl/controller/systemstate/alwayson/AlwaysOnController.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.systemstate.alwayson; + +import java.util.Set; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.device.nature.ess.EssNature; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.api.exception.WriteChannelException; + +/** + * @author matthias.rossmann + */ +@ThingInfo(title = "Keep always running", description = "Tries to keep the Ess always running. Use if Off-Grid functionality is required.") +public class AlwaysOnController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + + /* + * Constructors + */ + public AlwaysOnController() { + super(); + } + + public AlwaysOnController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) + public final ConfigChannel> esss = new ConfigChannel>("esss", this); + + /* + * Methods + */ + @Override + public void run() { + try { + for (Ess ess : esss.value()) { + try { + ess.setWorkState.pushWriteFromLabel(EssNature.START); + } catch (WriteChannelException e) { + log.error("", e); + } + } + } catch (InvalidValueException e) { + log.error("No Storage Found!", e); + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } +} diff --git a/edge/src/io/openems/impl/controller/systemstate/alwayson/Ess.java b/edge/src/io/openems/impl/controller/systemstate/alwayson/Ess.java new file mode 100644 index 00000000000..3a904854a1f --- /dev/null +++ b/edge/src/io/openems/impl/controller/systemstate/alwayson/Ess.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.systemstate.alwayson; + +import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.WriteChannel; +import io.openems.api.controller.IsThingMap; +import io.openems.api.controller.ThingMap; +import io.openems.api.device.nature.ess.EssNature; + +@IsThingMap(type = EssNature.class) +public class Ess extends ThingMap { + + public final WriteChannel setWorkState; + public final ReadChannel systemState; + + public Ess(EssNature ess) { + super(ess); + setWorkState = ess.setWorkState().required(); + systemState = ess.systemState().required(); + } + +} diff --git a/edge/src/io/openems/impl/controller/systemstate/powerthreshold/Ess.java b/edge/src/io/openems/impl/controller/systemstate/powerthreshold/Ess.java new file mode 100644 index 00000000000..f94686bb07d --- /dev/null +++ b/edge/src/io/openems/impl/controller/systemstate/powerthreshold/Ess.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.systemstate.powerthreshold; + +import java.util.ArrayList; +import java.util.List; + +import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.WriteChannel; +import io.openems.api.controller.IsThingMap; +import io.openems.api.controller.ThingMap; +import io.openems.api.device.nature.ess.AsymmetricEssNature; +import io.openems.api.device.nature.ess.EssNature; +import io.openems.api.device.nature.ess.SymmetricEssNature; + +@IsThingMap(type = EssNature.class) +public class Ess extends ThingMap { + + public final WriteChannel setWorkState; + public final ReadChannel systemState; + public final ReadChannel soc; + public final ReadChannel minSoc; + private List> activePowerChannels = new ArrayList<>(); + + public enum State { + ON, OFF, UNKNOWN + } + + public State currentState = State.UNKNOWN; + + public Ess(EssNature ess) { + super(ess); + setWorkState = ess.setWorkState().required(); + systemState = ess.systemState().required(); + this.minSoc = ess.minSoc().required(); + this.soc = ess.soc().required(); + if (ess instanceof SymmetricEssNature) { + SymmetricEssNature e = (SymmetricEssNature) ess; + activePowerChannels.add(e.activePower().required()); + } else if (ess instanceof AsymmetricEssNature) { + AsymmetricEssNature e = (AsymmetricEssNature) ess; + activePowerChannels.add(e.activePowerL1().required()); + activePowerChannels.add(e.activePowerL2().required()); + activePowerChannels.add(e.activePowerL3().required()); + } + } + + public Long getPower() { + Long power = null; + for (ReadChannel powerChannel : activePowerChannels) { + if (powerChannel.valueOptional().isPresent()) { + if (power == null) { + power = powerChannel.valueOptional().get(); + } else { + power += powerChannel.valueOptional().get(); + } + } + } + return power; + } + +} diff --git a/edge/src/io/openems/impl/controller/systemstate/powerthreshold/Meter.java b/edge/src/io/openems/impl/controller/systemstate/powerthreshold/Meter.java new file mode 100644 index 00000000000..86a16ec294a --- /dev/null +++ b/edge/src/io/openems/impl/controller/systemstate/powerthreshold/Meter.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.systemstate.powerthreshold; + +import java.util.ArrayList; +import java.util.List; + +import io.openems.api.channel.ReadChannel; +import io.openems.api.controller.IsThingMap; +import io.openems.api.controller.ThingMap; +import io.openems.api.device.nature.meter.AsymmetricMeterNature; +import io.openems.api.device.nature.meter.MeterNature; +import io.openems.api.device.nature.meter.SymmetricMeterNature; + +@IsThingMap(type = MeterNature.class) +public class Meter extends ThingMap { + + private List> activePowerChannels = new ArrayList<>(); + + public Meter(MeterNature meter) { + super(meter); + if (meter instanceof SymmetricMeterNature) { + SymmetricMeterNature m = (SymmetricMeterNature) meter; + activePowerChannels.add(m.activePower().required()); + } else if (meter instanceof AsymmetricMeterNature) { + AsymmetricMeterNature m = (AsymmetricMeterNature) meter; + activePowerChannels.add(m.activePowerL1().required()); + activePowerChannels.add(m.activePowerL2().required()); + activePowerChannels.add(m.activePowerL3().required()); + } + } + + public Long getPower() { + Long power = null; + for (ReadChannel powerChannel : activePowerChannels) { + if (powerChannel.valueOptional().isPresent()) { + if (power == null) { + power = powerChannel.valueOptional().get(); + } else { + power += powerChannel.valueOptional().get(); + } + } + } + return power; + } + +} diff --git a/edge/src/io/openems/impl/controller/systemstate/powerthreshold/ThresholdOnController.java b/edge/src/io/openems/impl/controller/systemstate/powerthreshold/ThresholdOnController.java new file mode 100644 index 00000000000..8ab060903e9 --- /dev/null +++ b/edge/src/io/openems/impl/controller/systemstate/powerthreshold/ThresholdOnController.java @@ -0,0 +1,142 @@ +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.systemstate.powerthreshold; + +import java.util.Set; + +import com.google.common.base.Optional; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.device.nature.ess.EssNature; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.api.exception.WriteChannelException; +import io.openems.impl.controller.systemstate.powerthreshold.Ess.State; + +/** + * @author matthias.rossmann + */ +@ThingInfo(title = "Stop if not useable", description = "Starts the ess if the GridFeed power is lager than a defined threshold. The ess will be stoped if the ess are empty and the GridFeed power is below a defined threshold.") +public class ThresholdOnController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + + /* + * Constructors + */ + public ThresholdOnController() { + super(); + } + + public ThresholdOnController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) + public final ConfigChannel> esss = new ConfigChannel>("esss", this); + + @ChannelInfo(title = "Grid-Meter", description = "Sets the grid meter.", type = Meter.class) + public final ConfigChannel meter = new ConfigChannel("meter", this); + + @ChannelInfo(title = "Power Threshold Start", description = "If the Grid-Feed Power is lager than this Threshold, the System will be started", type = Long.class) + public final ConfigChannel onThreshold = new ConfigChannel<>("onThreshold", this); + @ChannelInfo(title = "Power Threshold Stop", description = "If the Grid-Feed Power is smaler than this Threshold and the ess is empty, the System will be stopped.", type = Long.class) + public final ConfigChannel offThreshold = new ConfigChannel<>("offThreshold", this); + @ChannelInfo(title = "Time Lag Start", description = "The time the power has to be above the onThreshold to start the ess.", type = Long.class) + public final ConfigChannel onTimelag = new ConfigChannel<>("onTimelag", this); + @ChannelInfo(title = "Time Lag Stop", description = "The time,in minutes, the power has to be below the offThreshold to stop the ess.", type = Long.class) + public final ConfigChannel offTimelag = new ConfigChannel<>("offTimelag", this); + + /* + * Fields + */ + private long timePowerAboveStartThreshold = System.currentTimeMillis(); + private long timePowerBelowStopThreshold = System.currentTimeMillis(); + + /* + * Methods + */ + @SuppressWarnings("unlikely-arg-type") + @Override + public void run() { + try { + long calculatedPower = meter.value().getPower(); + for (Ess ess : esss.value()) { + calculatedPower += ess.getPower(); + } + if (calculatedPower >= onThreshold.value()) { + timePowerAboveStartThreshold = System.currentTimeMillis(); + } + if (calculatedPower < offThreshold.value()) { + timePowerBelowStopThreshold = System.currentTimeMillis(); + } + for (Ess ess : esss.value()) { + switch (ess.currentState) { + case OFF: + if (System.currentTimeMillis() - timePowerAboveStartThreshold > onTimelag.value() * 1000 * 60) { + ess.currentState = State.ON; + } else { + try { + ess.setWorkState.pushWriteFromLabel(EssNature.STOP); + } catch (WriteChannelException e) { + log.error("", e); + } + } + break; + case ON: + if (System.currentTimeMillis() - timePowerBelowStopThreshold > offTimelag.value() * 1000 * 60 + && ess.soc.value() <= ess.minSoc.value()) { + ess.currentState = State.OFF; + } else { + try { + ess.setWorkState.pushWriteFromLabel(EssNature.START); + } catch (WriteChannelException e) { + log.error("", e); + } + } + break; + case UNKNOWN: + default: + if (ess.systemState.labelOptional().equals(Optional.of(EssNature.STOP))) { + ess.currentState = State.OFF; + } else { + ess.currentState = State.ON; + } + break; + } + + } + } catch (InvalidValueException e) { + log.error("No Storage Found!", e); + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } +} diff --git a/edge/src/io/openems/impl/controller/systemstate/time/Ess.java b/edge/src/io/openems/impl/controller/systemstate/time/Ess.java new file mode 100644 index 00000000000..096cba1c93e --- /dev/null +++ b/edge/src/io/openems/impl/controller/systemstate/time/Ess.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.systemstate.time; + +import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.WriteChannel; +import io.openems.api.controller.IsThingMap; +import io.openems.api.controller.ThingMap; +import io.openems.api.device.nature.ess.EssNature; + +@IsThingMap(type = EssNature.class) +public class Ess extends ThingMap { + + public final WriteChannel setWorkState; + public final ReadChannel systemState; + + public Ess(EssNature ess) { + super(ess); + setWorkState = ess.setWorkState().required(); + systemState = ess.systemState().required(); + } + +} diff --git a/edge/src/io/openems/impl/controller/systemstate/time/TimeOnController.java b/edge/src/io/openems/impl/controller/systemstate/time/TimeOnController.java new file mode 100644 index 00000000000..9881fbd6753 --- /dev/null +++ b/edge/src/io/openems/impl/controller/systemstate/time/TimeOnController.java @@ -0,0 +1,155 @@ +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.systemstate.time; + +import java.time.LocalTime; +import java.util.Optional; +import java.util.Set; + +import io.openems.api.channel.Channel; +import io.openems.api.channel.ChannelChangeListener; +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.device.nature.ess.EssNature; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.api.exception.WriteChannelException; +import io.openems.common.session.Role; + +/** + * @author matthias.rossmann + */ +@ThingInfo(title = "Keep always running", description = "Tries to keep the Ess always running. Use if Off-Grid functionality is required.") +public class TimeOnController extends Controller implements ChannelChangeListener { + + private ThingStateChannels thingState = new ThingStateChannels(this); + + /* + * Constructors + */ + public TimeOnController() { + super(); + } + + public TimeOnController(String thingId) { + super(thingId); + } + + /* + * Config + */ + @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) + public final ConfigChannel> esss = new ConfigChannel>("esss", this); + + @ChannelInfo(title = "Time-On", description = "", type = String.class, writeRoles = { Role.OWNER }) + public ConfigChannel timeOn = new ConfigChannel("timeOn", this).addChangeListener(this); + @ChannelInfo(title = "Time-Off", description = "", type = String.class, writeRoles = { Role.OWNER }) + public ConfigChannel timeOff = new ConfigChannel("timeOff", this).addChangeListener(this); + + /* + * Fields + */ + private LocalTime timeStart; + private LocalTime timeStop; + + enum State { + START, STOP + } + + private State currentState = State.STOP; + + /* + * Methods + */ + @Override + public void run() { + try { + System.out.println(currentState.toString()); + switch (currentState) { + case START: + if (isOpen(timeStop, timeStart, LocalTime.now())) { + this.currentState = State.STOP; + } else { + for (Ess ess : esss.value()) { + System.out.println(ess.systemState.value()); + try { + ess.setWorkState.pushWriteFromLabel(EssNature.START); + } catch (WriteChannelException e) { + log.error("", e); + } + } + } + break; + case STOP: + if (isOpen(timeStart, timeStop, LocalTime.now())) { + this.currentState = State.START; + } else { + for (Ess ess : esss.value()) { + System.out.println(ess.systemState.value()); + try { + ess.setWorkState.pushWriteFromLabel(EssNature.STOP); + } catch (WriteChannelException e) { + log.error("", e); + } + } + } + break; + default: + log.error("no state set."); + break; + } + } catch (InvalidValueException e) { + log.error("No Storage Found!", e); + } + } + + public static boolean isOpen(LocalTime start, LocalTime end, LocalTime time) { + if (start.isAfter(end)) { + return !time.isBefore(start) || !time.isAfter(end); + } else { + return !time.isBefore(start) && !time.isAfter(end); + } + } + + @Override + public void channelChanged(Channel channel, Optional newValue, Optional oldValue) { + if (channel.equals(timeOn)) { + if (newValue.isPresent()) { + timeStart = LocalTime.parse((String) newValue.get()); + } else { + timeStart = null; + } + } else if (channel.equals(timeOff)) { + if (newValue.isPresent()) { + timeStop = LocalTime.parse((String) newValue.get()); + } else { + timeStop = null; + } + } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } +} diff --git a/edge/src/io/openems/impl/controller/testwrite/TestWriteController.java b/edge/src/io/openems/impl/controller/testwrite/TestWriteController.java index b6f01d62c71..0bd38872623 100644 --- a/edge/src/io/openems/impl/controller/testwrite/TestWriteController.java +++ b/edge/src/io/openems/impl/controller/testwrite/TestWriteController.java @@ -1,67 +1,74 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.testwrite; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.controller.Controller; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; -import io.openems.api.exception.WriteChannelException; - -@ThingInfo(title = "Test write") -public class TestWriteController extends Controller { - - /* - * Config - */ - @ChannelInfo(title = "Output", type = Output.class) - public ConfigChannel out = new ConfigChannel<>("out", this); - - @ChannelInfo(title = "Input", type = Input.class) - public ConfigChannel in = new ConfigChannel<>("in", this); - - /* - * Methods - */ - @Override - public void run() { - try { - out.value().output1.pushWrite(true); - log.info(in.value().input1.value().toString()); - } catch (WriteChannelException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (InvalidValueException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - // for (Ess ess : esss) { - // try { - // ess.setActivePower.pushWrite(500L); - // ess.setWorkState.pushWriteFromLabel(SymmetricEssNature.START); - // } catch (WriteChannelException e) { - // log.error("", e); - // } - // } - } - -} +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.controller.testwrite; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.controller.Controller; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.InvalidValueException; +import io.openems.api.exception.WriteChannelException; + +@ThingInfo(title = "Test write") +public class TestWriteController extends Controller { + + private ThingStateChannels thingState = new ThingStateChannels(this); + /* + * Config + */ + @ChannelInfo(title = "Output", type = Output.class) + public ConfigChannel out = new ConfigChannel<>("out", this); + + @ChannelInfo(title = "Input", type = Input.class) + public ConfigChannel in = new ConfigChannel<>("in", this); + + /* + * Methods + */ + @Override + public void run() { + try { + out.value().output1.pushWrite(true); + log.info(in.value().input1.value().toString()); + } catch (WriteChannelException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvalidValueException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // for (Ess ess : esss) { + // try { + // ess.setActivePower.pushWrite(500L); + // ess.setWorkState.pushWriteFromLabel(SymmetricEssNature.START); + // } catch (WriteChannelException e) { + // log.error("", e); + // } + // } + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + +} diff --git a/edge/src/io/openems/impl/controller/thermalpowerstation/ThermalPowerStationController.java b/edge/src/io/openems/impl/controller/thermalpowerstation/ThermalPowerStationController.java index ac706b85948..c86466401b8 100644 --- a/edge/src/io/openems/impl/controller/thermalpowerstation/ThermalPowerStationController.java +++ b/edge/src/io/openems/impl/controller/thermalpowerstation/ThermalPowerStationController.java @@ -26,6 +26,7 @@ import io.openems.api.channel.Channel; import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; @@ -50,6 +51,7 @@ private enum State { private int switchOnCount = 0; private int switchOffCount = 0; private State currentState = State.UNDEFINED; + private ThingStateChannels thingState = new ThingStateChannels(this); /* * Constructors @@ -239,4 +241,9 @@ private long getProductionPower() throws InvalidValueException { return power; } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/device/Readme.md b/edge/src/io/openems/impl/device/Readme.md index e5696bf72d1..63464f0a01b 100644 --- a/edge/src/io/openems/impl/device/Readme.md +++ b/edge/src/io/openems/impl/device/Readme.md @@ -13,6 +13,7 @@ * [KMTronic Relay board Output](kmtronic/Readme.md) * [KEBA KeContact EVCS](keba/Readme.md) * [Custom: Riedmann PLC](custom/riedmann/Readme.md) +* [FENECON Pro ESS](pro/Readme.md) * [Simulated Grid Meter](simulator/Readme.md) * [Simulator Output](simulator/Readme.md) * [FENECON Commercial ESS](commercial/Readme.md) diff --git a/edge/src/io/openems/impl/device/bcontrol/BControl.java b/edge/src/io/openems/impl/device/bcontrol/BControl.java index dbcc94a993f..2512607fe05 100644 --- a/edge/src/io/openems/impl/device/bcontrol/BControl.java +++ b/edge/src/io/openems/impl/device/bcontrol/BControl.java @@ -22,7 +22,8 @@ public BControl(Bridge parent) throws OpenemsException { * Config */ @ChannelInfo(title = "Meter", description = "Sets the meter nature.", type = BControlMeter.class) - public final ConfigChannel meter = new ConfigChannel<>("meter", this); + public final ConfigChannel meter = new ConfigChannel("meter", this) + .addChangeListener(this); /* * Methods @@ -35,4 +36,5 @@ protected Set getDeviceNatures() { } return natures; } + } diff --git a/edge/src/io/openems/impl/device/bcontrol/BControlMeter.java b/edge/src/io/openems/impl/device/bcontrol/BControlMeter.java index b32d37154f9..56eae465f9f 100644 --- a/edge/src/io/openems/impl/device/bcontrol/BControlMeter.java +++ b/edge/src/io/openems/impl/device/bcontrol/BControlMeter.java @@ -3,6 +3,7 @@ import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.FunctionalReadChannel; import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.meter.AsymmetricMeterNature; import io.openems.api.device.nature.meter.SymmetricMeterNature; @@ -18,8 +19,11 @@ @ThingInfo(title = "B-Control Energy Meter") public class BControlMeter extends ModbusDeviceNature implements SymmetricMeterNature, AsymmetricMeterNature { + private ThingStateChannels thingState; + public BControlMeter(String thingId, Device parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); } /* @@ -268,4 +272,9 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { }, apparentPowerPos, apparentPowerNeg).unit("VA"); return mp; } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } } diff --git a/edge/src/io/openems/impl/device/byd/Bem125ktla01.java b/edge/src/io/openems/impl/device/byd/Bem125ktla01.java index c4073abb549..08d454ea019 100644 --- a/edge/src/io/openems/impl/device/byd/Bem125ktla01.java +++ b/edge/src/io/openems/impl/device/byd/Bem125ktla01.java @@ -48,7 +48,7 @@ public Bem125ktla01(Bridge parent) throws OpenemsException { * Config */ @ChannelInfo(title = "Ess", description = "Sets the Ess nature.", type = Bem125ktla01Ess.class) - public final ConfigChannel ess = new ConfigChannel("ess", this); + public final ConfigChannel ess = new ConfigChannel("ess", this).addChangeListener(this); /* * Methods diff --git a/edge/src/io/openems/impl/device/byd/Bem125ktla01Ess.java b/edge/src/io/openems/impl/device/byd/Bem125ktla01Ess.java index 5d37bf711b4..d0360d811ae 100644 --- a/edge/src/io/openems/impl/device/byd/Bem125ktla01Ess.java +++ b/edge/src/io/openems/impl/device/byd/Bem125ktla01Ess.java @@ -23,13 +23,13 @@ import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.ReadChannel; import io.openems.api.channel.StaticValueChannel; -import io.openems.api.channel.StatusBitChannel; -import io.openems.api.channel.StatusBitChannels; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.ess.SymmetricEssNature; import io.openems.api.doc.ThingInfo; import io.openems.api.exception.ConfigException; +import io.openems.impl.protocol.modbus.ModbusBitWrappingChannel; import io.openems.impl.protocol.modbus.ModbusDeviceNature; import io.openems.impl.protocol.modbus.ModbusReadChannel; import io.openems.impl.protocol.modbus.ModbusReadLongChannel; @@ -69,6 +69,7 @@ public ConfigChannel chargeSoc() { /* * Inherited Channels */ + private ThingStateChannels thingState = new ThingStateChannels(this); private ModbusReadChannel soc; private StaticValueChannel allowedCharge = new StaticValueChannel("AllowedCharge", this, 0L); private StaticValueChannel allowedDischarge = new StaticValueChannel("AllowedDischarge", this, 0L); @@ -84,12 +85,10 @@ public ConfigChannel chargeSoc() { private ModbusWriteChannel setWorkState; private StaticValueChannel maxNominalPower = new StaticValueChannel<>("maxNominalPower", this, 0L); private StaticValueChannel capacity = new StaticValueChannel<>("capacity", this, 170000L).unit("Wh"); - public StatusBitChannels warning; public ModbusReadChannel sysAlarmInfo; - public StatusBitChannel sysWorkStatus; - public StatusBitChannel sysControlMode; - public StatusBitChannel sysAlarmInfo2; + public ModbusReadChannel sysWorkStatus; + public ModbusReadChannel sysControlMode; public ModbusReadChannel batteryStackVoltage; public ModbusReadChannel batteryStackCurrent; public ModbusReadChannel batteryStackPower; @@ -133,11 +132,6 @@ public ReadChannel allowedApparent() { return allowedApparent; } - @Override - public StatusBitChannels warning() { - return warning; - } - @Override public WriteChannel setWorkState() { return setWorkState; @@ -178,60 +172,59 @@ public WriteChannel setReactivePower() { */ @Override protected ModbusProtocol defineModbusProtocol() throws ConfigException { - warning = new StatusBitChannels("Warning", this); return new ModbusProtocol( // new ModbusRegisterRange(0x0100, // new UnsignedWordElement(0x100, // - sysAlarmInfo = new ModbusReadLongChannel("SysAlarmInfo", this)// - .label(0, "Warning State")// - .label(1, "Protection State")// - .label(2, "Derating State")// - .label(4, "Charge Forbidden").label(16, "Discharge Forbidden")), + new ModbusBitWrappingChannel("SysAlarmInfo", this, this.thingState)// + .warningBit(0, WarningEss.WarningState)// + .warningBit(1, WarningEss.ProtectionState)// + .warningBit(2, WarningEss.DeratingState)// + .warningBit(3, WarningEss.ChargeForbidden)// + .warningBit(4, WarningEss.DischargeForbidden)// + ),// + new UnsignedWordElement(0x101, // - sysWorkStatus = new StatusBitChannel("SysWorkStatus", this)// - .label(0, "Initial") // - .label(1, "Fault") // - .label(2, "Stop") // - .label(4, "Hot Standby") // - .label(8, "Monitoring") // - .label(16, "Standby") // - .label(32, "Operation") // - .label(64, "Debug")), // + sysWorkStatus = new ModbusReadLongChannel("SysWorkStatus", this)// + .label(1, "Initial") // + .label(2, "Fault") // + .label(4, "Stop") // + .label(8, "Hot Standby") // + .label(16, "Monitoring") // + .label(32, "Standby") // + .label(64, "Operation") // + .label(128, "Debug")), // new UnsignedWordElement(0x102, // - sysControlMode = new StatusBitChannel("SysControlMode", this)// - .label(0, "Remote") // - .label(1, "Local")), // + sysControlMode = new ModbusReadLongChannel("SysControlMode", this)// + .label(1, "Remote") // + .label(2, "Local")), // new DummyElement(0x103)), new ModbusRegisterRange(0x0110, // new UnsignedWordElement(0x110, // - sysAlarmInfo = new StatusBitChannel("SysAlarmInfo", this)// - .label(0, "Status abnormal of AC surge protector") // - .label(1, "Close of control switch") // - .label(2, "Emergency stop") // - .label(4, "Status abnormal of frog detector") // - .label(8, "Serious leakage") // - .label(16, "Normal_leakage")), // + new ModbusBitWrappingChannel("SysAlarmInfo", this, thingState)// + .warningBit(1, WarningEss.StatusAbnormalOfACSurgeProtector) // Status abnormal of AC surge protector + .warningBit(2, WarningEss.CloseOfControlSwitch) // Close of control switch + .warningBit(3, WarningEss.EmergencyStop) // Emergency stop + .warningBit(5, WarningEss.StatusAbnormalOfFrogDetector) // Status_abnormal_of_frog_detector + .warningBit(6, WarningEss.SeriousLeakage) // Serious_leakage + .warningBit(7, WarningEss.NormalLeakage)), // Normal_leakage new UnsignedWordElement(0x111, // - sysAlarmInfo2 = new StatusBitChannel("SysAlarmInfo2", this)// - .label(0, "Failure of temperature sensor in control cabinet") // - .label(1, "Close of control switch") // - /* - * TODO new OnOffBitItem(9, "Failure_of_humidity_sensor_in_control_cabinet"), // - * new OnOffBitItem(12, "Failure_of_storage_device"), // - * new OnOffBitItem(13, "Exceeding_of_humidity_in_control_cabinet")))); - */ - )), new ModbusRegisterRange(0x1300, new UnsignedWordElement(0x1300, // - batteryStackVoltage = new ModbusReadLongChannel("BatteryStackVoltage", this) - .multiplier(2).unit("mV")), + new ModbusBitWrappingChannel("SysAlarmInfo2", this, thingState)// + .warningBit(0, WarningEss.FailureOfTemperatureSensorInControlCabinet) // Failure of temperature sensor in control cabinet + .warningBit(9, WarningEss.FailureOfHumiditySensorInControlCabinet) // Failure_of_humidity_sensor_in_control_cabinet + .warningBit(12,WarningEss.FailureOfStorageDevice) // Failure_of_storage_device + .warningBit(13,WarningEss.ExceedingOfHumidityInControlCabinet)) // Exceeding_of_humidity_in_control_cabinet + + ), new ModbusRegisterRange(0x1300, new UnsignedWordElement(0x1300, // + batteryStackVoltage = new ModbusReadLongChannel("BatteryStackVoltage", this).multiplier(2) + .unit("mV")), new UnsignedWordElement(0x1301, // batteryStackCurrent = new ModbusReadLongChannel("BatteryStackCurrent", this) - .multiplier(2).unit("mA")), + .multiplier(2).unit("mA")), new UnsignedWordElement(0x1302, // - batteryStackPower = new ModbusReadLongChannel("BatteryStackPower", this) - .multiplier(2).unit("W")), + batteryStackPower = new ModbusReadLongChannel( + "BatteryStackPower", this).multiplier(2).unit("W")), new UnsignedWordElement(0x1303, // - batteryStackSoc = soc = new ModbusReadLongChannel("BatteryStackSoc", this) - .unit("%")), + batteryStackSoc = soc = new ModbusReadLongChannel("BatteryStackSoc", this).unit("%")), new UnsignedWordElement(0x1304, // batteryStackSoh = new ModbusReadLongChannel("BatteryStackSoh", this).unit("%")), new UnsignedWordElement(0x1305, // @@ -250,15 +243,20 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { batteryStackTotalCapacity = new ModbusReadLongChannel( "BatteryStackTotalCapacity", this).unit("Wh")), new UnsignedDoublewordElement(0x130A, // - batteryStackTotalCharge = new ModbusReadLongChannel("BatteryStackTotalCharge", - this).unit("kWh")), + batteryStackTotalCharge = new ModbusReadLongChannel("BatteryStackTotalCharge", this) + .unit("kWh")), new UnsignedDoublewordElement(0x130C, // - batteryStackTotalDischarge = new ModbusReadLongChannel( - "BatteryStackTotalDischarge", this).unit("kWh")))); + batteryStackTotalDischarge = new ModbusReadLongChannel("BatteryStackTotalDischarge", + this).unit("kWh")))); } @Override public StaticValueChannel capacity() { return capacity; } + + @Override + public ThingStateChannels getStateChannel() { + return thingState; + } } diff --git a/edge/src/io/openems/impl/device/byd/WarningEss.java b/edge/src/io/openems/impl/device/byd/WarningEss.java new file mode 100644 index 00000000000..ec153c243d7 --- /dev/null +++ b/edge/src/io/openems/impl/device/byd/WarningEss.java @@ -0,0 +1,22 @@ +package io.openems.impl.device.byd; + +import io.openems.api.channel.thingstate.WarningEnum; + +public enum WarningEss implements WarningEnum { + + WarningState(0), ProtectionState(1), DeratingState(2), ChargeForbidden(3), DischargeForbidden(4), StatusAbnormalOfACSurgeProtector(5), + CloseOfControlSwitch(6), EmergencyStop(7), StatusAbnormalOfFrogDetector(8), SeriousLeakage(9), NormalLeakage(10), + FailureOfTemperatureSensorInControlCabinet(11), FailureOfHumiditySensorInControlCabinet(12), FailureOfStorageDevice(13), + ExceedingOfHumidityInControlCabinet(14); + + public final int value; + + private WarningEss(int value) { + this.value = value; + } + + @Override + public int getValue() { + return this.value; + } +} diff --git a/edge/src/io/openems/impl/device/carlogavazzi/em300series/EM300.java b/edge/src/io/openems/impl/device/carlogavazzi/em300series/EM300.java index ec79b02e489..728f6398046 100644 --- a/edge/src/io/openems/impl/device/carlogavazzi/em300series/EM300.java +++ b/edge/src/io/openems/impl/device/carlogavazzi/em300series/EM300.java @@ -45,7 +45,7 @@ public EM300(Bridge parent) throws OpenemsException { * Config */ @ChannelInfo(title = "Meter", description = "Sets the meter nature.", type = EM300Meter.class) - public final ConfigChannel meter = new ConfigChannel<>("meter", this); + public final ConfigChannel meter = new ConfigChannel("meter", this).addChangeListener(this); /* * Methods diff --git a/edge/src/io/openems/impl/device/carlogavazzi/em300series/EM300Meter.java b/edge/src/io/openems/impl/device/carlogavazzi/em300series/EM300Meter.java index e0765d2b88e..64a2b4456b8 100644 --- a/edge/src/io/openems/impl/device/carlogavazzi/em300series/EM300Meter.java +++ b/edge/src/io/openems/impl/device/carlogavazzi/em300series/EM300Meter.java @@ -22,6 +22,7 @@ import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.meter.AsymmetricMeterNature; import io.openems.api.device.nature.meter.SymmetricMeterNature; @@ -40,11 +41,14 @@ @ThingInfo(title = "Socomec Meter") public class EM300Meter extends ModbusDeviceNature implements SymmetricMeterNature, AsymmetricMeterNature { + private ThingStateChannels thingState; + /* * Constructors */ public EM300Meter(String thingId, Device parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); } /* @@ -206,44 +210,49 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { currentL3 = new ModbusReadLongChannel("CurrentL3", this).unit("mA")), new SignedDoublewordElement(19, // activePowerL1 = new ModbusReadLongChannel("ActivePowerL1", this).unit("W") - .multiplier(-1)), + .multiplier(-1)), new SignedDoublewordElement(21, // activePowerL2 = new ModbusReadLongChannel("ActivePowerL2", this).unit("W") - .multiplier(-1)), + .multiplier(-1)), new SignedDoublewordElement(23, // activePowerL3 = new ModbusReadLongChannel("ActivePowerL3", this).unit("W") - .multiplier(-1)), + .multiplier(-1)), new SignedDoublewordElement(25, // reactivePowerL1 = new ModbusReadLongChannel("ReactivePowerL1", this).unit("var") - .multiplier(-1)), + .multiplier(-1)), new SignedDoublewordElement(27, // reactivePowerL2 = new ModbusReadLongChannel("ReactivePowerL2", this).unit("var") - .multiplier(-1)), + .multiplier(-1)), new SignedDoublewordElement(29, // reactivePowerL3 = new ModbusReadLongChannel("ReactivePowerL3", this) - .unit("var").multiplier(-1)), + .unit("var").multiplier(-1)), new DummyElement(31, 40), new SignedDoublewordElement(41, // activePower = new ModbusReadLongChannel("ActivePower", this).unit("W").multiplier(-1)), new SignedDoublewordElement(43, // apparentPower = new ModbusReadLongChannel("ApparentPower", this).unit("VA") - .multiplier(-1)), + .multiplier(-1)), new SignedDoublewordElement(45, // reactivePower = new ModbusReadLongChannel("ReactivePower", this) - .unit("var").multiplier(-1))), + .unit("var").multiplier(-1))), new ModbusInputRegisterRange(52, new SignedWordElement(52, // frequency = new ModbusReadLongChannel("Frequency", this).unit("mHZ").multiplier(2)), new UnsignedDoublewordElement(53, // activePositiveEnergy = new ModbusReadLongChannel("ActivePositiveEnergy", this) - .unit("kWh").multiplier(1)), + .unit("kWh").multiplier(1)), new UnsignedDoublewordElement(55, // reactivePositiveEnergy = new ModbusReadLongChannel("ReactivePositiveEnergy", this) - .unit("kvarh").multiplier(-1))), + .unit("kvarh").multiplier(-1))), new ModbusRegisterRange(79, // new UnsignedDoublewordElement(79, // activeNegativeEnergy = new ModbusReadLongChannel( "ActiveNegativeEnergy", this).unit("kWh").multiplier(-1)), new UnsignedDoublewordElement(81, // reactiveNegativeEnergy = new ModbusReadLongChannel("ReactiveNegativeEnergy", this) - .unit("kvarh").multiplier(-1)))); + .unit("kvarh").multiplier(-1)))); + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; } } diff --git a/edge/src/io/openems/impl/device/commercial/FaultCharger.java b/edge/src/io/openems/impl/device/commercial/FaultCharger.java new file mode 100644 index 00000000000..34358945692 --- /dev/null +++ b/edge/src/io/openems/impl/device/commercial/FaultCharger.java @@ -0,0 +1,88 @@ +package io.openems.impl.device.commercial; + +import io.openems.api.channel.thingstate.FaultEnum; + +public enum FaultCharger implements FaultEnum{ + HighVoltageSideOfDCConverterUndervoltage(0), HighVoltageSideOfDCConverterOvervoltage(1), LowVoltageSideOfDCConverterUndervoltage(2), + LowVoltageSideOfDCConverterOvervoltage(3), HighVoltageSideOfDCConverterOvercurrentFault(4), LowVoltageSideOfDCConverterOvercurrentFault(5), DCConverterIGBTFault(6), DCConverterPrechargeUnmet(7), + BECUCommunicationDisconnected(8), DCConverterCommunicationDisconnected(9), CurrentConfigurationOverRange(10), TheBatteryRequestStop(11), OvercurrentRelayFault(12), LightningProtectionDeviceFault(13), + DCConverterPriamaryContactorDisconnectedAbnormally(14), DCDisconnectedAbnormallyOnLowVoltageSideOfDCConvetor(15), DCConvetorEEPROMAbnormity1(16), DCConvetorEEPROMAbnormity1Second(17), + EDCConvetorEEPROMAbnormity1(18), DCConvertorGeneralOverload(19), DCShortCircuit(20), PeakPulseCurrentProtection(21), DCDisconnectAbnormallyOnHighVoltageSideOfDCConvetor(22), EffectivePulseValueOverhigh(23), + DCConverteSevereOverload(24), DCBreakerDisconnectAbnormallyOnHighVoltageSideOfDCConvetor(25), DCBreakerDisconnectAbnormallyOnLowVoltageSideOfDCConvetor(26), DCConvetorPrechargeContactorCloseFailed(27), + DCConvetorMainContactorCloseFailed(28), ACContactorStateAbnormityOfDCConvetor(29), DCConvetorEmergencyStop(30), DCConverterChargingGunDisconnected(31), DCCurrentAbnormityBeforeDCConvetorWork(32), FuSeDisconnected(33), + DCConverterHardwareCurrentOrVoltageFault(34), DCConverterCrystalOscillatorCircuitInvalidation(35), DCConverterResetCircuitInvalidation(36), DCConverterSamplingCircuitInvalidation(37), + DCConverterDigitalIOCircuitInvalidation(38), DCConverterPWMCircuitInvalidation(39), DCConverterX5045CircuitInvalidation(40), DCConverterCANCircuitInvalidation(41), DCConverterSoftwareANDHardwareProtectionCircuitInvalidation(42), + DCConverterPowerCircuitInvalidation(43), DCConverterCPUInvalidation(44), DCConverterTINT0InterruptInvalidation(45), DCConverterADCInterruptInvalidation(46), DCConverterCAPITN4InterruptInvalidation(47), + DCConverterCAPINT6InterruptInvalidation(48), DCConverterT3PINTinterruptInvalidation(49), DCConverterT4PINTinterruptInvalidation(50), DCConverterPDPINTAInterruptInvalidation(51), DCConverterT1PINTInterruptInvalidation(52), + DCConverterRESVInterruptInvalidation(53), DCConverter100usTaskInvalidation(54), DCConverterClockInvalidation(55), DCConverterEMSMemoryInvalidation(56), DCConverterExteriorCommunicationInvalidation(57), + DCConverterIOInterfaceInvalidation(58), DCConverterInputVoltageBoundFault(59), DCConverterOutterVoltageBoundFault(60), DCConverterOutputVoltageBoundFault(61), DCConverterInductCurrentBoundFault(62), + DCConverterInputCurrentBoundFault(63), DCConverterOutputCurrentBoundFault(64), DCReactorOverTemperature(65), DCIGBTOverTemperature(66), DCConverterChanel3OverTemperature(67), DCConverterChanel4OverTemperature(68), + DCConverterChanel5OverTemperature(69), DCConverterChanel6OverTemperature(70), DCConverterChanel7OverTemperature(71), DCConverterChanel8OverTemperature(72), DCReactorTemperatureSamplingInvalidation(73), DCIGBTTemperatureSamplingInvalidation(74), + DCConverterChanel3TemperatureSamplingInvalidation(75), DCConverterChanel4TemperatureSamplingInvalidation(76), DCConverterChanel5TemperatureSamplingInvalidation(77), DCConverterChanel6TemperatureSamplingInvalidation(78), + DCConverterChanel7TemperatureSamplingInvalidation(79), DCConverterChanel8TemperatureSamplingInvalidation(80), DCConverterInductanceCurrentSamplingInvalidation(81), CurrentSamplingInvalidationOnTheLowVoltageSideOfDCConverter(82), + VoltageSamplingInvalidationOnTheLowVoltageSideOfDCConverter(83), InsulationInspectionFault(84), NegContactorCloseUnsuccessly(85), NegContactorCutWhenRunning(86), BmsDCDC1HighVoltageSideOfDCConverterUndervoltage(87), + BmsDCDC1HighVoltageSideOfDCConverterOvervoltage(88), BmsDCDC1LowVoltageSideOfDCConverterUndervoltage(89), BmsDCDC1LowVoltageSideOfDCConverterOvervoltage(90), BmsDCDC1HighVoltageSideOfDCConverterOvercurrentFault(91), + BmsDCDC1LowVoltageSideOfDCConverterOvercurrentFault(92), BmsDCDC1DCConverterIGBTFault(93), BmsDCDC1DCConverterPrechargeUnmet(94), BmsDCDC1BECUCommunicationDisconnected(95), BmsDCDC1DCConverterCommunicationDisconnected(96), + BmsDCDC1CurrentConfigurationOverRange(97), BmsDCDC1TheBatteryRequestStop(98), BmsDCDC1OvercurrentRelayFault(99), BmsDCDC1LightningProtectionDeviceFault(100), BmsDCDC1DCConverterPriamaryContactorDisconnectedAbnormally(101), + BmsDCDC1DCDisconnectedAbnormallyOnLowVoltageSideOfDCConvetor(102), BmsDCDC1DCConvetorEEPROMAbnormity1(103), BmsDCDC1DCConvetorEEPROMAbnormity1Second(104), BmsDCDC1EDCConvetorEEPROMAbnormity1(105), BsmDCDC1DCConvertorGeneralOverload(106), + BsmDCDC1DCShortCircuit(107), BsmDCDC1PeakPulseCurrentProtection(108), BsmDCDC1DCDisconnectAbnormallyOnHighVoltageSideOfDCConvetor(109), BsmDCDC1EffectivePulseValueOverhigh(110), BsmDCDC1DCConverteSevereOverload(111), + BsmDCDC1DCBreakerDisconnectAbnormallyOnHighVoltageSideOfDCConvetor(112), BsmDCDC1DCBreakerDisconnectAbnormallyOnLowVoltageSideOfDCConvetor(113), BsmDCDC1DCConvetorPrechargeContactorCloseFailed(114), BsmDCDC1DCConvetorMainContactorCloseFailed(115), + BsmDCDC1ACContactorStateAbnormityOfDCConvetor(116), BsmDCDC1DCConvetorEmergencyStop(117), BsmDCDC1DCConverterChargingGunDisconnected(118), BsmDCDC1DCCurrentAbnormityBeforeDCConvetorWork(119), BsmDCDC1FuSeDisconnected(120), + BsmDCDC1DCConverterHardwareCurrentOrVoltageFault(121), BmsDCDC1DCConverterCrystalOscillatorCircuitInvalidation(122), BmsDCDC1DCConverterResetCircuitInvalidation(123), BmsDCDC1DCConverterSamplingCircuitInvalidation(124), + BmsDCDC1DCConverterDigitalIOCircuitInvalidation(125), BmsDCDC1DCConverterPWMCircuitInvalidation(126), BmsDCDC1DCConverterX5045CircuitInvalidation(127), BmsDCDC1DCConverterCANCircuitInvalidation(128), + BmsDCDC1DCConverterSoftwareANDHardwareProtectionCircuitInvalidation(129), BmsDCDC1DCConverterPowerCircuitInvalidation(130), BmsDCDC1DCConverterCPUInvalidation(131), BmsDCDC1DCConverterTINT0InterruptInvalidation(132), + BmsDCDC1DCConverterADCInterruptInvalidation(133), BmsDCDC1DCConverterCAPITN4InterruptInvalidation(134), BmsDCDC1DCConverterCAPINT6InterruptInvalidation(135), BmsDCDC1DCConverterT3PINTinterruptInvalidation(136), + BmsDCDC1DCConverterT4PINTinterruptInvalidation(137), BmsDCDC1DCConverterPDPINTAInterruptInvalidation(138), BmsDCDC1DCConverterT1PINTInterruptInvalidationSecond(139), BmsDCDC1DCConverterRESVInterruptInvalidation(140), + BmsDCDC1DCConverter100usTaskInvalidation(141), BmsDCDC1DCConverterClockInvalidation(142), BmsDCDC1DCConverterEMSMemoryInvalidation(143), BmsDCDC1DCConverterExteriorCommunicationInvalidation(144), BmsDCDC1DCConverterIOInterfaceInvalidation(145), + BmsDCDC1DCConverterInputVoltageBoundFault(146), BmsDCDC1DCConverterOutterVoltageBoundFault(147), BmsDCDC1DCConverterOutputVoltageBoundFault(148), BmsDCDC1DCConverterInductCurrentBoundFault(149), BmsDCDC1DCConverterInputCurrentBoundFault(150), + BmsDCDC1DCConverterOutputCurrentBoundFault(151), BmsDCDC1DCReactorOverTemperature(152), BmsDCDC1DCIGBTOverTemperature(153), BmsDCDC1DCConverterChanel3OverTemperature(154), BmsDCDC1DCConverterChanel4OverTemperature(155), + BmsDCDC1DCConverterChanel5OverTemperature(156), BmsDCDC1DCConverterChanel6OverTemperature(157), BmsDCDC1DCConverterChanel7OverTemperature(158), BmsDCDC1DCConverterChanel8OverTemperature(159), BmsDCDC1DCReactorTemperatureSamplingInvalidation(160), + BmsDCDC1DCIGBTTemperatureSamplingInvalidation(161), BmsDCDC1DCConverterChanel3TemperatureSamplingInvalidation(162), BmsDCDC1DCConverterChanel4TemperatureSamplingInvalidation(163), BmsDCDC1DCConverterChanel5TemperatureSamplingInvalidation(164), + BmsDCDC1DCConverterChanel6TemperatureSamplingInvalidation(165), BmsDCDC1DCConverterChanel7TemperatureSamplingInvalidation(166), BmsDCDC1DCConverterChanel8TemperatureSamplingInvalidation(167), BmsDCDC1DCConverterInductanceCurrentSamplingInvalidation(168), + BmsDCDC1CurrentSamplingInvalidationOnTheLowVoltageSideOfDCConverter(169), BmsDCDC1VoltageSamplingInvalidationOnTheLowVoltageSideOfDCConverter(170), BmsDCDC1InsulationInspectionFault(171), BmsDCDC1NegContactorCloseUnsuccessly(172), + BmsDCDC1NegContactorCutWhenRunning(173), PvDCDCHighVoltageSideOfDCConverterUndervoltage(174), PvDCDCHighVoltageSideOfDCConverterOvervoltage(175), PvDCDCLowVoltageSideOfDCConverterUndervoltage(176), PvDCDCLowVoltageSideOfDCConverterOvervoltage(177), + PvDCDCHighVoltageSideOfDCConverterOvercurrentFault(178), PvDCDCLowVoltageSideOfDCConverterOvercurrentFault(179), PvDCDCDCConverterIGBTFault(180), PvDCDCDCConverterPrechargeUnmet(181), PvDCDCBECUCommunicationDisconnected(182), + PvDCDCDCConverterCommunicationDisconnected(183), PvDCDCCurrentConfigurationOverRange(184), PvDCDCTheBatteryRequestStop(185), PvDCDCOvercurrentRelayFault(186), PvDCDCLightningProtectionDeviceFault(187), + PvDCDCDCConverterPriamaryContactorDisconnectedAbnormally(188), PvDCDCDCDisconnectedAbnormallyOnLowVoltageSideOfDCConvetor(189), PvDCDCDCConvetorEEPROMAbnormity1(190), PvDCDCDCConvetorEEPROMAbnormity1Second(191), PvDCDCEDCConvetorEEPROMAbnormity1(192), + PvDCDCDCConvertorGeneralOverload(193), PvDCDCDCShortCircuit(194), PvDCDCPeakPulseCurrentProtection(195), PvDCDCDCDisconnectAbnormallyOnHighVoltageSideOfDCConvetor(196), PvDCDCEffectivePulseValueOverhigh(197), PvDCDCDCConverteSevereOverload(198), + PvDCDCDCBreakerDisconnectAbnormallyOnHighVoltageSideOfDCConvetor(199), PvDCDCDCBreakerDisconnectAbnormallyOnLowVoltageSideOfDCConvetor(200), PvDCDCDCConvetorPrechargeContactorCloseFailed(201), PvDCDCDCConvetorMainContactorCloseFailed(202), + PvDCDCACContactorStateAbnormityOfDCConvetor(203), PvDCDCDCConvetorEmergencyStop(204), PvDCDCDCConverterChargingGunDisconnected(205), PvDCDCDCCurrentAbnormityBeforeDCConvetorWork(206), PvDCDCFuSeDisconnected(207), PvDCDCDCConverterHardwareCurrentOrVoltageFault(208), + PvDCDCDCConverterCrystalOscillatorCircuitInvalidation(209), PvDCDCDCConverterResetCircuitInvalidation(210), PvDCDCDCConverterSamplingCircuitInvalidation(211), PvDCDCDCConverterDigitalIOCircuitInvalidation(212), PvDCDCDCConverterPWMCircuitInvalidation(213), + PvDCDCDCConverterX5045CircuitInvalidation(214), PvDCDCDCConverterCANCircuitInvalidation(215), PvDCDCDCConverterSoftwareANDHardwareProtectionCircuitInvalidation(216), PvDCDCDCConverterPowerCircuitInvalidation(217), PvDCDCDCConverterCPUInvalidation(218), + PvDCDCDCConverterTINT0InterruptInvalidation(219), PvDCDCDCConverterADCInterruptInvalidation(220), PvDCDCDCConverterCAPITN4InterruptInvalidation(221), PvDCDCDCConverterCAPINT6InterruptInvalidation(222), PvDCDCDCConverterT3PINTinterruptInvalidation(223), + PvDCDCDCConverterT4PINTinterruptInvalidation(224), PvDCDCConverterPDPINTAInterruptInvalidation(225), PvDCDCConverterT1PINTInterruptInvalidationSecond(226), PvDCDCConverterRESVInterruptInvalidation(227), PvDCDCConverter100usTaskInvalidation(228), + PvDCDCConverterClockInvalidation(229), PvDCDCConverterEMSMemoryInvalidation(230), PvDCDCConverterExteriorCommunicationInvalidation(231), PvDCDCConverterIOInterfaceInvalidation(232), PvDCDCConverterInputVoltageBoundFault(233), + PvDCDCConverterOutterVoltageBoundFault(234), PvDCDCConverterOutputVoltageBoundFault(235), PvDCDCConverterInductCurrentBoundFault(236), PvDCDCConverterInputCurrentBoundFault(237), PvDCDCConverterOutputCurrentBoundFault(238), PvDCDCDCReactorOverTemperature(239), + PvDCDCDCIGBTOverTemperature(240), PvDCDCDCConverterChanel3OverTemperature(241), PvDCDCDCConverterChanel4OverTemperature(242), PvDCDCDCConverterChanel5OverTemperature(243), PvDCDCDCConverterChanel6OverTemperature(244), + PvDCDCDCConverterChanel7OverTemperature(245), PvDCDCDCConverterChanel8OverTemperature(246), PvDCDCDCReactorTemperatureSamplingInvalidation(247), PvDCDCDCIGBTTemperatureSamplingInvalidation(248), PvDCDCDCConverterChanel3TemperatureSamplingInvalidation(249), + PvDCDCDCConverterChanel4TemperatureSamplingInvalidation(250), PvDCDCDCConverterChanel5TemperatureSamplingInvalidation(251), PvDCDCDCConverterChanel6TemperatureSamplingInvalidation(252), PvDCDCDCConverterChanel7TemperatureSamplingInvalidation(253), + PvDCDCDCConverterChanel8TemperatureSamplingInvalidation(254), PvDCDCDCConverterInductanceCurrentSamplingInvalidation(255), PvDCDCCurrentSamplingInvalidationOnTheLowVoltageSideOfDCConverter(256), PvDCDCVoltageSamplingInvalidationOnTheLowVoltageSideOfDCConverter(257), + PvDCDCInsulationInspectionFault(258), PvDCDCNegContactorCloseUnsuccessly(259), PvDCDCNegContactorCutWhenRunning(260), PvDCDC1HighVoltageSideOfDCConverterUndervoltage(261), PvDCDC1HighVoltageSideOfDCConverterOvervoltage(262), PvDCDC1LowVoltageSideOfDCConverterUndervoltage(263), + PvDCDC1LowVoltageSideOfDCConverterOvervoltage(264), PvDCDC1HighVoltageSideOfDCConverterOvercurrentFault(265), PvDCDC1LowVoltageSideOfDCConverterOvercurrentFault(266), PvDCDC1DCConverterIGBTFault(267), PvDCDC1DCConverterPrechargeUnmet(268), PvDCDC1BECUCommunicationDisconnected(269), + PvDCDC1DCConverterCommunicationDisconnected(270), PvDCDC1CurrentConfigurationOverRange(271), PvDCDC1TheBatteryRequestStop(272), PvDCDC1OvercurrentRelayFault(273), PvDCDC1LightningProtectionDeviceFault(274), PvDCDC1DCConverterPriamaryContactorDisconnectedAbnormally(275), + PvDCDC1DCDisconnectedAbnormallyOnLowVoltageSideOfDCConvetor(276), PvDCDC1DCConvetorEEPROMAbnormity1(277), PvDCDC1DCConvetorEEPROMAbnormity1Second(278), PvDCDC1EDCConvetorEEPROMAbnormity1(279), PvDCDC1DCConvertorGeneralOverload(280), PvDCDC1DCShortCircuit(281), + PvDCDC1PeakPulseCurrentProtection(282), PvDCDC1DCDisconnectAbnormallyOnHighVoltageSideOfDCConvetor(283), PvDCDC1EffectivePulseValueOverhigh(284), PvDCDC1DCConverteSevereOverload(285), PvDCDC1DCBreakerDisconnectAbnormallyOnHighVoltageSideOfDCConvetor(286), + PvDCDC1DCBreakerDisconnectAbnormallyOnLowVoltageSideOfDCConvetor(287), PvDCDC1DCConvetorPrechargeContactorCloseFailed(288), PvDCDC1DCConvetorMainContactorCloseFailed(289), PvDCDC1ACContactorStateAbnormityOfDCConvetor(290), PvDCDC1DCConvetorEmergencyStop(291), + PvDCDC1DCConverterChargingGunDisconnected(292), PvDCDC1DCCurrentAbnormityBeforeDCConvetorWork(293), PvDCDC1FuSeDisconnected(294), PvDCDC1DCConverterHardwareCurrentOrVoltageFault(295), PvDCDC1DCConverterCrystalOscillatorCircuitInvalidation(296), PvDCDC1DCConverterResetCircuitInvalidation(297), + PvDCDC1DCConverterSamplingCircuitInvalidation(298), PvDCDC1DCConverterDigitalIOCircuitInvalidation(299), PvDCDC1DCConverterPWMCircuitInvalidation(300), PvDCDC1DCConverterX5045CircuitInvalidation(301), PvDCDC1DCConverterCANCircuitInvalidation(302), + PvDCDC1DCConverterSoftwareANDHardwareProtectionCircuitInvalidation(303), PvDCDC1DCConverterPowerCircuitInvalidation(304), PvDCDC1DCConverterCPUInvalidation(305), PvDCDC1DCConverterTINT0InterruptInvalidation(306), PvDCDC1DCConverterADCInterruptInvalidation(307), + PvDCDC1DCConverterCAPITN4InterruptInvalidation(308), PvDCDC1DCConverterCAPINT6InterruptInvalidation(309), PvDCDC1DCConverterT3PINTinterruptInvalidation(310), PvDCDC1DCConverterT4PINTinterruptInvalidation(311), PvDCDC1DCConverterPDPINTAInterruptInvalidation(312), + PvDCDC1DCConverterT1PINTInterruptInvalidationSecond(313), PvDCDC1DCConverterRESVInterruptInvalidation(314), PvDCDC1DCConverter100usTaskInvalidation(315), PvDCDC1DCConverterClockInvalidation(316), PvDCDC1DCConverterEMSMemoryInvalidation(317), + PvDCDC1DCConverterExteriorCommunicationInvalidation(318), PvDCDC1DCConverterIOInterfaceInvalidation(319), PvDCDC1DCConverterInputVoltageBoundFault(320), PvDCDC1DCConverterOutterVoltageBoundFault(321), PvDCDC1DCConverterOutputVoltageBoundFault(322), + PvDCDC1DCConverterInductCurrentBoundFault(323), PvDCDC1DCConverterInputCurrentBoundFault(324), PvDCDC1DCConverterOutputCurrentBoundFault(325), PvDCDC1DCReactorOverTemperature(326), PvDCDC1DCIGBTOverTemperature(327), PvDCDC1DCConverterChanel3OverTemperature(328), + PvDCDC1DCConverterChanel4OverTemperature(329), PvDCDC1DCConverterChanel5OverTemperature(330), PvDCDC1DCConverterChanel6OverTemperature(331), PvDCDC1DCConverterChanel7OverTemperature(332), PvDCDC1DCConverterChanel8OverTemperature(333), PvDCDC1DCReactorTemperatureSamplingInvalidation(334), + PvDCDC1DCIGBTTemperatureSamplingInvalidation(335), PvDCDC1DCConverterChanel3TemperatureSamplingInvalidation(336), PvDCDC1DCConverterChanel4TemperatureSamplingInvalidation(337), PvDCDC1DCConverterChanel5TemperatureSamplingInvalidation(338), PvDCDC1DCConverterChanel6TemperatureSamplingInvalidation(339), + PvDCDC1DCConverterChanel7TemperatureSamplingInvalidation(340), PvDCDC1DCConverterChanel8TemperatureSamplingInvalidation(341), PvDCDC1DCConverterInductanceCurrentSamplingInvalidation(342), PvDCDC1CurrentSamplingInvalidationOnTheLowVoltageSideOfDCConverter(343), + PvDCDC1VoltageSamplingInvalidationOnTheLowVoltageSideOfDCConverter(344), PvDCDC1InsulationInspectionFault(345), PvDCDC1NegContactorCloseUnsuccessly(346), PvDCDC1NegContactorCutWhenRunning(347); + + private final int value; + + private FaultCharger(int value) { + this.value = value; + } + + @Override + public int getValue() { + return this.value; + } +} diff --git a/edge/src/io/openems/impl/device/commercial/FaultEss.java b/edge/src/io/openems/impl/device/commercial/FaultEss.java new file mode 100644 index 00000000000..0e8e7f15c90 --- /dev/null +++ b/edge/src/io/openems/impl/device/commercial/FaultEss.java @@ -0,0 +1,35 @@ +package io.openems.impl.device.commercial; + +import io.openems.api.channel.thingstate.FaultEnum; + +public enum FaultEss implements FaultEnum { + + DCPrechargeContactorCloseUnsuccessfully(0), ACPrechargeContactorCloseUnsuccessfully(1), ACMainContactorCloseUnsuccessfully(2), DCElectricalBreaker1CloseUnsuccessfully(3), + DCMainContactorCloseUnsuccessfully(4), ACBreakerTrip(5), ACMainContactorOpenWhenRunning(6), DCMainContactorOpenWhenRunning(7), ACMainContactorOpenUnsuccessfully(8), + DCElectricalBreaker1OpenUnsuccessfully(9), DCMainContactorOpenUnsuccessfully(10), HardwarePDPFault(11), MasterStopSuddenly(12), DCShortCircuitProtection(13), DCOvervoltageProtection(14), + DCUndervoltageProtection(15), DCInverseNoConnectionProtection(16), DCDisconnectionProtection(17), CommutingVoltageAbnormityProtection(18), DCOvercurrentProtection(19), + Phase1PeakCurrentOverLimitProtection(20), Phase2PeakCurrentOverLimitProtection(21), Phase3PeakCurrentOverLimitProtection(22), Phase1GridVoltageSamplingInvalidation(23), + Phase2VirtualCurrentOverLimitProtection(24), Phase3VirtualCurrentOverLimitProtection(25), Phase1GridVoltageSamplingInvalidation2(26), Phase2ridVoltageSamplingInvalidation(27), + Phase3GridVoltageSamplingInvalidation(28), Phase1InvertVoltageSamplingInvalidation(29), Phase2InvertVoltageSamplingInvalidation(30), Phase3InvertVoltageSamplingInvalidation(31), + ACCurrentSamplingInvalidation(32), DCCurrentSamplingInvalidation(33), Phase1OvertemperatureProtection(34), Phase2OvertemperatureProtection(35), Phase3OvertemperatureProtection(36), + Phase1TemperatureSamplingInvalidation(37), Phase2TemperatureSamplingInvalidation(38), Phase3TemperatureSamplingInvalidation(39), Phase1PrechargeUnmetProtection(40), Phase2PrechargeUnmetProtection(41), + Phase3PrechargeUnmetProtection(42), UnadaptablePhaseSequenceErrorProtection(43), DSPProtection(44), Phase1GridVoltageSevereOvervoltageProtection(45),Phase1GridVoltageGeneralOvervoltageProtection(46), + Phase2GridVoltageSevereOvervoltageProtection(47), Phase2GridVoltageGeneralOvervoltageProtection(48), Phase3GridVoltageSevereOvervoltageProtection(49), Phase3GridVoltageGeneralOvervoltageProtection(50), + Phase1GridVoltageSevereUndervoltageProtection(51), Phase1GridVoltageGeneralUndervoltageProtection(52), Phase2GridVoltageSevereUndervoltageProtection(53), Phase2GridVoltageGeneralUndervoltageProtection(54), + Phase3GridVoltageSevereUndervoltageProtection(55), Phase3GridVoltageGeneralUndervoltageProtection(56), SevereOverfrequncyProtection(57), GeneralOverfrequncyProtection(58), SevereUnderfrequncyProtection(59), + GeneralsUnderfrequncyProtection(60), Phase1Gridloss(61), Phase2Gridloss(62), Phase3Gridloss(63), IslandingProtection(64), Phase1UnderVoltageRideThrough(65), Phase2UnderVoltageRideThrough(66), + Phase3UnderVoltageRideThrough(67), Phase1InverterVoltageSevereOvervoltageProtection(68), Phase1InverterVoltageGeneralOvervoltageProtection(69), Phase2InverterVoltageSevereOvervoltageProtection(70), + Phase2InverterVoltageGeneralOvervoltageProtection(71), Phase3InverterVoltageSevereOvervoltageProtection(72), Phase3InverterVoltageGeneralOvervoltageProtection(73), + InverterPeakVoltageHighProtectionCauseByACDisconnect(74); + + private final int value; + + private FaultEss(int value) { + this.value = value; + } + + @Override + public int getValue() { + return this.value; + } +} diff --git a/edge/src/io/openems/impl/device/commercial/FeneconCommercialAC.java b/edge/src/io/openems/impl/device/commercial/FeneconCommercialAC.java index 20deb3e77a4..d4efd99fa95 100644 --- a/edge/src/io/openems/impl/device/commercial/FeneconCommercialAC.java +++ b/edge/src/io/openems/impl/device/commercial/FeneconCommercialAC.java @@ -45,7 +45,7 @@ public FeneconCommercialAC(Bridge parent) throws OpenemsException { * Config */ @ChannelInfo(title = "Ess", description = "Sets the Ess nature.", type = FeneconCommercialEss.class) - public final ConfigChannel ess = new ConfigChannel<>("ess", this); + public final ConfigChannel ess = new ConfigChannel("ess", this).addChangeListener(this); /* * Methods diff --git a/edge/src/io/openems/impl/device/commercial/FeneconCommercialCharger.java b/edge/src/io/openems/impl/device/commercial/FeneconCommercialCharger.java index 544d9a8cd74..2a4badb246e 100644 --- a/edge/src/io/openems/impl/device/commercial/FeneconCommercialCharger.java +++ b/edge/src/io/openems/impl/device/commercial/FeneconCommercialCharger.java @@ -25,13 +25,14 @@ import io.openems.api.channel.ReadChannel; import io.openems.api.channel.StaticValueChannel; import io.openems.api.channel.StatusBitChannel; -import io.openems.api.channel.StatusBitChannels; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.charger.ChargerNature; import io.openems.api.doc.ThingInfo; import io.openems.api.exception.ConfigException; import io.openems.api.exception.InvalidValueException; +import io.openems.impl.protocol.modbus.ModbusBitWrappingChannel; import io.openems.impl.protocol.modbus.ModbusDeviceNature; import io.openems.impl.protocol.modbus.ModbusReadChannel; import io.openems.impl.protocol.modbus.ModbusReadLongChannel; @@ -54,13 +55,14 @@ public class FeneconCommercialCharger extends ModbusDeviceNature implements Char */ public FeneconCommercialCharger(String thingId, Device parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); + } /* * Inherited Channels */ - - public StatusBitChannels warning; + private ThingStateChannels thingState; public ModbusWriteChannel pvPowerLimitCommand; @@ -215,711 +217,777 @@ public ConfigChannel maxActualPower() { */ @Override protected ModbusProtocol defineModbusProtocol() throws ConfigException { - warning = new StatusBitChannels("Warning", this); ModbusProtocol protocol = new ModbusProtocol(// new WriteableModbusRegisterRange(0x0503, new UnsignedWordElement(0x0503, pvPowerLimitCommand = new ModbusWriteLongChannel("PvPowerLimitCommand", this).multiplier(2) - .unit("W"))), + .unit("W"))), new ModbusRegisterRange(0xA000, // new UnsignedWordElement(0xA000, bmsDCDCWorkState = new ModbusReadLongChannel("BmsDCDCWorkState", this)// - .label(2, "Initial")// - .label(4, "Stop")// - .label(8, "Ready")// - .label(16, "Running")// - .label(32, "Fault")// - .label(64, "Debug")// - .label(128, "Locked")), + .label(2, "Initial")// + .label(4, "Stop")// + .label(8, "Ready")// + .label(16, "Running")// + .label(32, "Fault")// + .label(64, "Debug")// + .label(128, "Locked")), new UnsignedWordElement(0xA001, bmsDCDCWorkMode = new ModbusReadLongChannel("BmsDCDCWorkMode", this)// - .label(128, "Constant Current")// - .label(256, "Constant Voltage")// - .label(512, "Boost MPPT"))), + .label(128, "Constant Current")// + .label(256, "Constant Voltage")// + .label(512, "Boost MPPT"))), new ModbusRegisterRange(0xA100, // - new UnsignedWordElement(0xA100, - bmsDCDCSuggestiveInformation1 = warning - .channel(new StatusBitChannel("BmsDCDCSuggestiveInformation1", this)// - .label(1, "Current sampling channel abnormity on high voltage side")// - .label(2, "Current sampling channel abnormity on low voltage side")// - .label(64, "EEPROM parameters over range")// - .label(128, "Update EEPROM failed")// - .label(256, "Read EEPROM failed")// - .label(512, "Current sampling channel abnormity before inductance"))), - new UnsignedWordElement(0xA101, bmsDCDCSuggestiveInformation2 = warning - .channel(new StatusBitChannel("BmsDCDCSuggestiveInformation2", this)// - .label(1, "Reactor power decrease caused by overtemperature")// - .label(2, "IGBT power decrease caused by overtemperature")// - .label(4, "Temperature chanel3 power decrease caused by overtemperature")// - .label(8, "Temperature chanel4 power decrease caused by overtemperature")// - .label(16, "Temperature chanel5 power decrease caused by overtemperature")// - .label(32, "Temperature chanel6 power decrease caused by overtemperature")// - .label(64, "Temperature chanel7 power decrease caused by overtemperature")// - .label(128, "Temperature chanel8 power decrease caused by overtemperature")// - .label(256, "Fan 1 stop failed")// - .label(512, "Fan 2 stop failed")// - .label(1024, "Fan 3 stop failed")// - .label(2048, "Fan 4 stop failed")// - .label(4096, "Fan 1 sartup failed")// - .label(8192, "Fan 2 sartup failed")// - .label(16384, "Fan 3 sartup failed")// - .label(32768, "Fan 4 sartup failed"))), - new UnsignedWordElement(0xA102, - bmsDCDCSuggestiveInformation3 = warning - .channel(new StatusBitChannel("BmsDCDCSuggestiveInformation3", this)// - .label(1, "High voltage side overvoltage")// - .label(2, "High voltage side undervoltage")// - .label(4, "EEPROM parameters over range")// - .label(8, "High voltage side voltage change unconventionally"))), - new UnsignedWordElement(0xA103, bmsDCDCSuggestiveInformation4 = warning - .channel(new StatusBitChannel("BmsDCDCSuggestiveInformation4", this)// - .label(1, "Current abnormity before DC Converter work on high voltage side")// - .label(2, "Current abnormity before DC Converter work on low voltage side")// - .label(4, "Initial Duty Ratio abnormity before DC Converter work")// - .label(8, "Voltage abnormity before DC Converter work on high voltage side")// - .label(16, "Voltage abnormity before DC Converter work on low voltage side"))), + new UnsignedWordElement(0xA100,// + new ModbusBitWrappingChannel("BmsDCDCSuggestiveInformation1" , this, this.thingState)// + .warningBit(0, WarningCharger.CurrentSamplingChannelAbnormityOnHighVoltageSide)// + .warningBit(1, WarningCharger.CurrentSamplingChannelAbnormityOnLowVoltageSide)// + .warningBit(6, WarningCharger.EEPROMParametersOverRange)// + .warningBit(7, WarningCharger.UpdateEEPROMFailed)// + .warningBit(8, WarningCharger.ReadEEPROMFailed)// + .warningBit(9, WarningCharger.CurrentSamplingChannelAbnormityBeforeInductance)// + ),// + + new UnsignedWordElement(0xA101, // + new ModbusBitWrappingChannel("BmsDCDCSuggestiveInformation2", this, this.thingState)// + .warningBit(0, WarningCharger.ReactorPowerDecreaseCausedByOvertemperature)// + .warningBit(1, WarningCharger.IGBTPowerDecreaseCausedByOvertemperature)// + .warningBit(2, WarningCharger.TemperatureChanel3PowerDecreaseCausedByOvertemperature)// + .warningBit(3, WarningCharger.TemperatureChanel4PowerDecreaseCausedByOvertemperature)// + .warningBit(4, WarningCharger.TemperatureChanel5PowerDecreaseCausedByOvertemperature)// + .warningBit(5, WarningCharger.TemperatureChanel6PowerDecreaseCausedByOvertemperature)// + .warningBit(6, WarningCharger.TemperatureChanel7PowerDecreaseCausedByOvertemperature)// + .warningBit(7, WarningCharger.TemperatureChanel8PowerDecreaseCausedByOvertemperature)// + .warningBit(8, WarningCharger.Fan1StopFailed)// + .warningBit(9, WarningCharger.Fan2StopFailed)// + .warningBit(10,WarningCharger.Fan3StopFailed)// + .warningBit(11,WarningCharger.Fan4StopFailed)// + .warningBit(12,WarningCharger.Fan1StartupFailed)// + .warningBit(13,WarningCharger.Fan2StartupFailed)// + .warningBit(14,WarningCharger.Fan3StartupFailed)// + .warningBit(15,WarningCharger.Fan4StartupFailed)// + ),// + + new UnsignedWordElement(0xA102,// + new ModbusBitWrappingChannel("BmsDCDCSuggestiveInformation3", this, this.thingState)// + .warningBit(0, WarningCharger.HighVoltageSideOvervoltage)// + .warningBit(1, WarningCharger.HighVoltageSideUndervoltage)// + .warningBit(2, WarningCharger.HighVoltageSideVoltageChangeUnconventionally)// + ),// + + new UnsignedWordElement(0xA103, // + new ModbusBitWrappingChannel("BmsDCDCSuggestiveInformation4", this, this.thingState)// + .warningBit(0, WarningCharger.CurrentAbnormityBeforeDCConverterWorkOnHighVoltageSide) + .warningBit(1, WarningCharger.CurrentAbnormityBeforeDCConverterWorkOnLowVoltageSXide) + .warningBit(2, WarningCharger.InitialDutyRatioAbnormityBeforeDCConverterWork) + .warningBit(3, WarningCharger.VoltageAbnormityBeforeDCConverterWorkOnHighVoltageSide) + .warningBit(4, WarningCharger.VoltageAbnormityBeforeDCConverterWorkOnLowVoltageSide) + ),// + new UnsignedWordElement(0xA104, - bmsDCDCSuggestiveInformation5 = warning - .channel(new StatusBitChannel("BmsDCDCSuggestiveInformation5", this)// - .label(1, "High voltage breaker inspection abnormity")// - .label(2, "Low voltage breaker inspection abnormity")// - .label(4, "DC precharge contactor inspection abnormity")// - .label(8, "DC precharge contactor open unsuccessfully")// - .label(16, "DC main contactor inspection abnormity")// - .label(32, "DC main contactor open unsuccessfully")// - .label(64, "Output contactor close unsuccessfully")// - .label(128, "Output contactor open unsuccessfully")// - .label(256, "AC main contactor close unsuccessfully")// - .label(512, "AC main contactor open unsuccessfully")// - .label(1024, "NegContactor open unsuccessfully")// - .label(2048, "NegContactor close unsuccessfully")// - .label(4096, "NegContactor state abnormal"))), + new ModbusBitWrappingChannel("BmsDCDCSuggestiveInformation5", this, this.thingState)// + .warningBit(0, WarningCharger.HighVoltageBreakerInspectionAbnormity)// + .warningBit(1, WarningCharger.LowVoltageBreakerInspectionAbnormity)// + .warningBit(2, WarningCharger.BsmDCDC5DCPrechargeContactorInspectionAbnormity)// + .warningBit(3, WarningCharger.DCPrechargeContactorOpenUnsuccessfully)// + .warningBit(4, WarningCharger.DCMainContactorInspectionAbnormity)// + .warningBit(5, WarningCharger.DCMainContactorOpenUnsuccessfully)// + .warningBit(6, WarningCharger.OutputContactorCloseUnsuccessfully)// + .warningBit(7, WarningCharger.OutputContactorOpenUnsuccessfully)// + .warningBit(8, WarningCharger.ACMainContactorCloseUnsuccessfully)// + .warningBit(9, WarningCharger.ACMainContactorOpenUnsuccessfully)// + .warningBit(10,WarningCharger.NegContactorOpenUnsuccessfully)// + .warningBit(11,WarningCharger.NegContactorCloseUnsuccessfully)// + .warningBit(12,WarningCharger.NegContactorStateAbnormal)// + ),// + new DummyElement(0xA105, 0xA10F), - new UnsignedWordElement(0xA110, - bmsDCDCAbnormity1 = warning.channel(new StatusBitChannel("BmsDCDCAbnormity1", this)// - .label(1, "High voltage side of DC Converter undervoltage")// - .label(2, "High voltage side of DC Converter overvoltage")// - .label(4, "Low voltage side of DC Converter undervoltage")// - .label(8, "Low voltage side of DC Converter overvoltage")// - .label(16, "High voltage side of DC Converter overcurrent fault")// - .label(32, "Low voltage side of DC Converter overcurrent fault")// - .label(64, "DC Converter IGBT fault")// - .label(128, "DC Converter Precharge unmet"))), + new UnsignedWordElement(0xA110,// + new ModbusBitWrappingChannel("BmsDCDCAbnormity1", this, this.thingState)// + .faultBit(0, FaultCharger.HighVoltageSideOfDCConverterUndervoltage)// + .faultBit(1, FaultCharger.HighVoltageSideOfDCConverterOvervoltage)// + .faultBit(2, FaultCharger.LowVoltageSideOfDCConverterUndervoltage)// + .faultBit(3, FaultCharger.LowVoltageSideOfDCConverterOvervoltage)// + .faultBit(4, FaultCharger.HighVoltageSideOfDCConverterOvercurrentFault)// + .faultBit(5, FaultCharger.LowVoltageSideOfDCConverterOvercurrentFault)// + .faultBit(6, FaultCharger.DCConverterIGBTFault)// + .faultBit(7, FaultCharger.DCConverterPrechargeUnmet)// + ),// + new UnsignedWordElement(0xA111, - bmsDCDCAbnormity2 = warning.channel(new StatusBitChannel("BmsDCDCAbnormity2", this)// - .label(1, "BECU communication disconnected")// - .label(2, "DC Converter communication disconnected")// - .label(4, "Current configuration over range")// - .label(8, "The battery request stop")// - .label(32, "Overcurrent relay fault")// - .label(64, "Lightning protection device fault")// - .label(128, "DC Converter priamary contactor disconnected abnormally")// - .label(512, "DC disconnected abnormally on low voltage side of DC convetor")// - .label(4096, "DC convetor EEPROM abnormity 1")// - .label(8192, "DC convetor EEPROM abnormity 1")// - .label(16384, "EDC convetor EEPROM abnormity 1"))), - new UnsignedWordElement(0xA112, - bmsDCDCAbnormity3 = warning.channel(new StatusBitChannel("BmsDCDCAbnormity3", this)// - .label(1, "DC Convertor general overload")// - .label(2, "DC short circuit")// - .label(4, "Peak pulse current protection")// - .label(8, "DC disconnect abnormally on high voltage side of DC convetor")// - .label(16, "Effective pulse value overhigh")// - .label(32, "DC Converte severe overload")// - .label(64, - "DC breaker disconnect abnormally on high voltage side of DC convetor")// - .label(128, - "DC breaker disconnect abnormally on low voltage side of DC convetor")// - .label(256, "DC convetor precharge contactor close failed ")// - .label(512, "DC convetor main contactor close failed")// - .label(1024, "AC contactor state abnormity of DC convetor")// - .label(2048, "DC convetor emergency stop")// - .label(4096, "DC converter charging gun disconnected")// - .label(8192, "DC current abnormity before DC convetor work")// - .label(16384, "Fuse disconnected")// - .label(32768, "DC converter hardware current or voltage fault"))), - new UnsignedWordElement(0xA113, - bmsDCDCAbnormity4 = warning.channel(new StatusBitChannel("BmsDCDCAbnormity4", this)// - .label(1, "DC converter crystal oscillator circuit invalidation")// - .label(2, "DC converter reset circuit invalidation")// - .label(4, "DC converter sampling circuit invalidation")// - .label(8, "DC converter digital I/O circuit invalidation")// - .label(16, "DC converter PWM circuit invalidation")// - .label(32, "DC converter X5045 circuit invalidation")// - .label(64, "DC converter CAN circuit invalidation")// - .label(128, "DC converter software&hardware protection circuit invalidation")// - .label(256, "DC converter power circuit invalidation")// - .label(512, "DC converter CPU invalidation")// - .label(1024, "DC converter TINT0 interrupt invalidation")// - .label(2048, "DC converter ADC interrupt invalidation")// - .label(4096, "DC converter CAPITN4 interrupt invalidation")// - .label(8192, "DC converter CAPINT6 interrupt invalidation")// - .label(16384, "DC converter T3PINTinterrupt invalidation")// - .label(32768, "DC converter T4PINTinterrupt invalidation"))), - new UnsignedWordElement(0xA114, - bmsDCDCAbnormity5 = warning.channel(new StatusBitChannel("BmsDCDCAbnormity5", this)// - .label(1, "DC converter PDPINTA interrupt invalidation")// - .label(2, "DC converter T1PINT interrupt invalidation")// - .label(4, "DC converter RESV interrupt invalidation")// - .label(8, "DC converter 100us task invalidation")// - .label(16, "DC converter clock invalidation")// - .label(32, "DC converter EMS memory invalidation")// - .label(64, "DC converter exterior communication invalidation")// - .label(128, "DC converter IO Interface invalidation")// - .label(256, "DC converter Input Voltage bound fault")// - .label(512, "DC converter Outter Voltage bound fault")// - .label(1024, "DC converter Output Voltage bound fault")// - .label(2048, "DC converter Induct Current bound fault")// - .label(4096, "DC converter Input Current bound fault")// - .label(8192, "DC converter Output Current bound fault"))), - new UnsignedWordElement(0xA115, - bmsDCDCAbnormity6 = warning.channel(new StatusBitChannel("BmsDCDCAbnormity6", this)// - .label(1, "DC Reactor over temperature")// - .label(2, "DC IGBT over temperature")// - .label(4, "DC Converter chanel 3 over temperature")// - .label(8, "DC Converter chanel 4 over temperature")// - .label(16, "DC Converter chanel 5 over temperature")// - .label(32, "DC Converter chanel 6 over temperature")// - .label(64, "DC Converter chanel 7 over temperature")// - .label(128, "DC Converter chanel 8 over temperature")// - .label(256, "DC Reactor temperature sampling invalidation")// - .label(512, "DC IGBT temperature sampling invalidation")// - .label(1024, "DC Converter chanel 3 temperature sampling invalidation")// - .label(2048, "DC Converter chanel 4 temperature sampling invalidation")// - .label(4096, "DC Converter chanel 5 temperature sampling invalidation")// - .label(8192, "DC Converter chanel 6 temperature sampling invalidation")// - .label(16384, "DC Converter chanel 7 temperature sampling invalidation")// - .label(32768, "DC Converter chanel 8 temperature sampling invalidation"))), + new ModbusBitWrappingChannel("BmsDCDCAbnormity2", this, this.thingState)// + .faultBit(0, FaultCharger.BECUCommunicationDisconnected)// + .faultBit(1, FaultCharger.DCConverterCommunicationDisconnected)// + .faultBit(2, FaultCharger.CurrentConfigurationOverRange)// + .faultBit(3, FaultCharger.TheBatteryRequestStop)// + .faultBit(5, FaultCharger.OvercurrentRelayFault)// + .faultBit(6, FaultCharger.LightningProtectionDeviceFault)// + .faultBit(7, FaultCharger.DCConverterPriamaryContactorDisconnectedAbnormally)// + .faultBit(9, FaultCharger.DCDisconnectedAbnormallyOnLowVoltageSideOfDCConvetor)// + .faultBit(12,FaultCharger.DCConvetorEEPROMAbnormity1)// + .faultBit(13,FaultCharger.DCConvetorEEPROMAbnormity1Second)// + .faultBit(14,FaultCharger.EDCConvetorEEPROMAbnormity1)// + ),// + + new UnsignedWordElement(0xA112,// + new ModbusBitWrappingChannel("BmsDCDCAbnormity3", this, this.thingState)// + .faultBit(0, FaultCharger.DCConvertorGeneralOverload)// + .faultBit(1, FaultCharger.DCShortCircuit)// + .faultBit(2, FaultCharger.PeakPulseCurrentProtection)// + .faultBit(3, FaultCharger.DCDisconnectAbnormallyOnHighVoltageSideOfDCConvetor)// + .faultBit(4, FaultCharger.EffectivePulseValueOverhigh)// + .faultBit(5, FaultCharger.DCConverteSevereOverload)// + .faultBit(6, FaultCharger.DCBreakerDisconnectAbnormallyOnHighVoltageSideOfDCConvetor)// + .faultBit(7, FaultCharger.DCBreakerDisconnectAbnormallyOnLowVoltageSideOfDCConvetor)// + .faultBit(8, FaultCharger.DCConvetorPrechargeContactorCloseFailed)// + .faultBit(9, FaultCharger.DCConvetorMainContactorCloseFailed)// + .faultBit(10,FaultCharger.ACContactorStateAbnormityOfDCConvetor)// + .faultBit(11,FaultCharger.DCConvetorEmergencyStop)// + .faultBit(12,FaultCharger.DCConverterChargingGunDisconnected)// + .faultBit(13,FaultCharger.DCCurrentAbnormityBeforeDCConvetorWork)// + .faultBit(14,FaultCharger.FuSeDisconnected)// + .faultBit(15,FaultCharger.DCConverterHardwareCurrentOrVoltageFault)// + ),// + + new UnsignedWordElement(0xA113,// + new ModbusBitWrappingChannel("BmsDCDCAbnormity4", this, this.thingState)// + .faultBit(0, FaultCharger.DCConverterCrystalOscillatorCircuitInvalidation)// + .faultBit(1, FaultCharger.DCConverterResetCircuitInvalidation)// + .faultBit(2, FaultCharger.DCConverterSamplingCircuitInvalidation)// + .faultBit(3, FaultCharger.DCConverterDigitalIOCircuitInvalidation)// + .faultBit(4, FaultCharger.DCConverterPWMCircuitInvalidation)// + .faultBit(5, FaultCharger.DCConverterX5045CircuitInvalidation)// + .faultBit(6, FaultCharger.DCConverterCANCircuitInvalidation)// + .faultBit(7, FaultCharger.DCConverterSoftwareANDHardwareProtectionCircuitInvalidation)// + .faultBit(8, FaultCharger.DCConverterPowerCircuitInvalidation)// + .faultBit(9, FaultCharger.DCConverterCPUInvalidation)// + .faultBit(10,FaultCharger.DCConverterTINT0InterruptInvalidation)// + .faultBit(11,FaultCharger.DCConverterADCInterruptInvalidation)// + .faultBit(12,FaultCharger.DCConverterCAPITN4InterruptInvalidation)// + .faultBit(13,FaultCharger.DCConverterCAPINT6InterruptInvalidation)// + .faultBit(14,FaultCharger.DCConverterT3PINTinterruptInvalidation)// + .faultBit(15,FaultCharger.DCConverterT4PINTinterruptInvalidation)// + ),// + + new UnsignedWordElement(0xA114,// + new ModbusBitWrappingChannel("BmsDCDCAbnormity5", this, this.thingState)// + .faultBit(0, FaultCharger.DCConverterPDPINTAInterruptInvalidation)// + .faultBit(1, FaultCharger.DCConverterT1PINTInterruptInvalidation)// + .faultBit(2, FaultCharger.DCConverterRESVInterruptInvalidation)// + .faultBit(3, FaultCharger.DCConverter100usTaskInvalidation)// + .faultBit(4, FaultCharger.DCConverterClockInvalidation)// + .faultBit(5, FaultCharger.DCConverterEMSMemoryInvalidation)// + .faultBit(6, FaultCharger.DCConverterExteriorCommunicationInvalidation)// + .faultBit(7, FaultCharger.DCConverterIOInterfaceInvalidation)// + .faultBit(8, FaultCharger.DCConverterInputVoltageBoundFault)// + .faultBit(9, FaultCharger.DCConverterOutterVoltageBoundFault)// + .faultBit(10,FaultCharger.DCConverterOutputVoltageBoundFault)// + .faultBit(11,FaultCharger.DCConverterInductCurrentBoundFault)// + .faultBit(12,FaultCharger.DCConverterInputCurrentBoundFault)// + .faultBit(13,FaultCharger.DCConverterOutputCurrentBoundFault)// + ),// + + new UnsignedWordElement(0xA115,// + new ModbusBitWrappingChannel("BmsDCDCAbnormity6", this, this.thingState)// + .faultBit(0, FaultCharger.DCReactorOverTemperature)// + .faultBit(1, FaultCharger.DCIGBTOverTemperature)// + .faultBit(2, FaultCharger.DCConverterChanel3OverTemperature)// + .faultBit(3, FaultCharger.DCConverterChanel4OverTemperature)// + .faultBit(4, FaultCharger.DCConverterChanel5OverTemperature)// + .faultBit(5, FaultCharger.DCConverterChanel6OverTemperature)// + .faultBit(6, FaultCharger.DCConverterChanel7OverTemperature)// + .faultBit(7, FaultCharger.DCConverterChanel8OverTemperature)// + .faultBit(8, FaultCharger.DCReactorTemperatureSamplingInvalidation)// + .faultBit(9, FaultCharger.DCIGBTTemperatureSamplingInvalidation)// + .faultBit(10,FaultCharger.DCConverterChanel3TemperatureSamplingInvalidation)// + .faultBit(11,FaultCharger.DCConverterChanel4TemperatureSamplingInvalidation)// + .faultBit(12,FaultCharger.DCConverterChanel5TemperatureSamplingInvalidation)// + .faultBit(13,FaultCharger.DCConverterChanel6TemperatureSamplingInvalidation)// + .faultBit(14,FaultCharger.DCConverterChanel7TemperatureSamplingInvalidation)// + .faultBit(15,FaultCharger.DCConverterChanel8TemperatureSamplingInvalidation)// + ),// + new UnsignedWordElement(0xA116, - bmsDCDCAbnormity7 = warning.channel(new StatusBitChannel("BmsDCDCAbnormity7", this)// - .label(32, "DC Converter inductance current sampling invalidation")// - .label(64, - "Current sampling invalidation on the low voltage sideof DC Converter")// - .label(128, - "Voltage sampling invalidation on the low voltage side of DC Converter")// - .label(256, "Insulation inspection fault")// - .label(512, "NegContactor close unsuccessly")// - .label(1024, "NegContactor cut When running"))), + new ModbusBitWrappingChannel("BmsDCDCAbnormity7", this, this.thingState)// + .faultBit(4, FaultCharger.DCConverterInductanceCurrentSamplingInvalidation)// + .faultBit(5, FaultCharger.CurrentSamplingInvalidationOnTheLowVoltageSideOfDCConverter)// + .faultBit(6, FaultCharger.VoltageSamplingInvalidationOnTheLowVoltageSideOfDCConverter)// + .faultBit(7, FaultCharger.InsulationInspectionFault)// + .faultBit(8, FaultCharger.NegContactorCloseUnsuccessly)// + .faultBit(9, FaultCharger.NegContactorCutWhenRunning)// + ),// + new DummyElement(0xA117, 0xA11F), new UnsignedWordElement(0xA120, bmsDCDCSwitchState = new StatusBitChannel("BmsDCDCSwitchState", this)// - .label(1, "DC precharge contactor")// - .label(2, "DC main contactor")// - .label(4, "Output contactor")// - .label(8, "Output breaker")// - .label(16, "Input breaker")// - .label(32, "AC contactor")// - .label(64, "Emergency stop button")// - .label(128, "NegContactor"))), + .label(1, "DC precharge contactor")// + .label(2, "DC main contactor")// + .label(4, "Output contactor")// + .label(8, "Output breaker")// + .label(16, "Input breaker")// + .label(32, "AC contactor")// + .label(64, "Emergency stop button")// + .label(128, "NegContactor"))), new ModbusRegisterRange(0xA130, // new SignedWordElement(0xA130, bmsDCDCOutputVoltage = new ModbusReadLongChannel("BmsDCDCOutputVoltage", this) - .unit("mV").multiplier(2)), + .unit("mV").multiplier(2)), new SignedWordElement(0xA131, bmsDCDCOutputCurrent = new ModbusReadLongChannel("BmsDCDCOutputCurrent", this) - .unit("mA").multiplier(2)), + .unit("mA").multiplier(2)), new SignedWordElement(0xA132, bmsDCDCOutputPower = new ModbusReadLongChannel("BmsDCDCOutputPower", this).unit("W") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0xA133, bmsDCDCInputVoltage = new ModbusReadLongChannel("BmsDCDCInputVoltage", this).unit("mV") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0xA134, bmsDCDCInputCurrent = new ModbusReadLongChannel("BmsDCDCInputCurrent", this).unit("mA") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0xA135, bmsDCDCInputPower = new ModbusReadLongChannel("BmsDCDCInputPower", this).unit("W") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0xA136, bmsDCDCInputEnergy = new ModbusReadLongChannel("BmsDCDCInputEnergy", this).unit("Wh") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0xA137, bmsDCDCOutputEnergy = new ModbusReadLongChannel("BmsDCDCOutputEnergy", this).unit("Wh") - .multiplier(2)), + .multiplier(2)), new DummyElement(0xA138, 0xA13F), new SignedWordElement(0xA140, bmsDCDCReactorTemperature = new ModbusReadLongChannel("BmsDCDCReactorTemperature", this) - .unit("°C")), + .unit("°C")), new SignedWordElement(0xA141, bmsDCDCIgbtTemperature = new ModbusReadLongChannel("BmsDCDCIgbtTemperature", this) - .unit("°C")), + .unit("°C")), new DummyElement(0xA142, 0xA14F), new UnsignedDoublewordElement(0xA150, bmsDCDCInputTotalChargeEnergy = new ModbusReadLongChannel( "BmsDCDCInputTotalChargeEnergy", this).unit("Wh").multiplier(2)) - .wordOrder(WordOrder.LSWMSW), + .wordOrder(WordOrder.LSWMSW), new UnsignedDoublewordElement(0xA152, bmsDCDCInputTotalDischargeEnergy = new ModbusReadLongChannel( "BmsDCDCInputTotalDischargeEnergy", this).unit("Wh").multiplier(2)) - .wordOrder(WordOrder.LSWMSW), + .wordOrder(WordOrder.LSWMSW), new UnsignedDoublewordElement(0xA154, bmsDCDCOutputTotalChargeEnergy = new ModbusReadLongChannel( "BmsDCDCOutputTotalChargeEnergy", this).unit("Wh").multiplier(2)) - .wordOrder(WordOrder.LSWMSW), + .wordOrder(WordOrder.LSWMSW), new UnsignedDoublewordElement(0xA156, bmsDCDCOutputTotalDischargeEnergy = new ModbusReadLongChannel( "BmsDCDCOutputTotalDischargeEnergy", this).unit("Wh") - .multiplier(2)).wordOrder(WordOrder.LSWMSW)), + .multiplier(2)).wordOrder(WordOrder.LSWMSW)), new ModbusRegisterRange(0xA300, // new UnsignedWordElement(0xA300, bmsDCDC1WorkState = new ModbusReadLongChannel("BmsDCDC1WorkState", this)// - .label(2, "Initial")// - .label(4, "Stop")// - .label(8, "Ready")// - .label(16, "Running")// - .label(32, "Fault")// - .label(64, "Debug")// - .label(128, "Locked")), + .label(2, "Initial")// + .label(4, "Stop")// + .label(8, "Ready")// + .label(16, "Running")// + .label(32, "Fault")// + .label(64, "Debug")// + .label(128, "Locked")), new UnsignedWordElement(0xA301, bmsDCDC1WorkMode = new ModbusReadLongChannel("BmsDCDC1WorkMode", this)// - .label(128, "Constant Current")// - .label(256, "Constant Voltage")// - .label(512, "Boost MPPT"))), + .label(128, "Constant Current")// + .label(256, "Constant Voltage")// + .label(512, "Boost MPPT"))), new ModbusRegisterRange(0xA400, // - new UnsignedWordElement(0xA400, - bmsDCDC1SuggestiveInformation1 = warning - .channel(new StatusBitChannel("BmsDCDC1SuggestiveInformation1", this)// - .label(1, "Current sampling channel abnormity on high voltage side")// - .label(2, "Current sampling channel abnormity on low voltage side")// - .label(64, "EEPROM parameters over range")// - .label(128, "Update EEPROM failed")// - .label(256, "Read EEPROM failed")// - .label(512, "Current sampling channel abnormity before inductance"))), - new UnsignedWordElement(0xA401, bmsDCDC1SuggestiveInformation2 = warning - .channel(new StatusBitChannel("BmsDCDC1SuggestiveInformation2", this)// - .label(1, "Reactor power decrease caused by overtemperature")// - .label(2, "IGBT power decrease caused by overtemperature")// - .label(4, "Temperature chanel3 power decrease caused by overtemperature")// - .label(8, "Temperature chanel4 power decrease caused by overtemperature")// - .label(16, "Temperature chanel5 power decrease caused by overtemperature")// - .label(32, "Temperature chanel6 power decrease caused by overtemperature")// - .label(64, "Temperature chanel7 power decrease caused by overtemperature")// - .label(128, "Temperature chanel8 power decrease caused by overtemperature")// - .label(256, "Fan 1 stop failed")// - .label(512, "Fan 2 stop failed")// - .label(1024, "Fan 3 stop failed")// - .label(2048, "Fan 4 stop failed")// - .label(4096, "Fan 1 sartup failed")// - .label(8192, "Fan 2 sartup failed")// - .label(16384, "Fan 3 sartup failed")// - .label(32768, "Fan 4 sartup failed"))), - new UnsignedWordElement(0xA402, - bmsDCDC1SuggestiveInformation3 = warning - .channel(new StatusBitChannel("BmsDCDC1SuggestiveInformation3", this)// - .label(1, "High voltage side overvoltage")// - .label(2, "High voltage side undervoltage")// - .label(4, "EEPROM parameters over range")// - .label(8, "High voltage side voltage change unconventionally"))), - new UnsignedWordElement(0xA403, bmsDCDC1SuggestiveInformation4 = warning - .channel(new StatusBitChannel("BmsDCDC1SuggestiveInformation4", this)// - .label(1, "Current abnormity before DC Converter work on high voltage side")// - .label(2, "Current abnormity before DC Converter work on low voltage side")// - .label(4, "Initial Duty Ratio abnormity before DC Converter work")// - .label(8, "Voltage abnormity before DC Converter work on high voltage side")// - .label(16, "Voltage abnormity before DC Converter work on low voltage side"))), - new UnsignedWordElement(0xA404, - bmsDCDC1SuggestiveInformation5 = warning - .channel(new StatusBitChannel("BmsDCDC1SuggestiveInformation5", this)// - .label(1, "High voltage breaker inspection abnormity")// - .label(2, "Low voltage breaker inspection abnormity")// - .label(4, "DC precharge contactor inspection abnormity")// - .label(8, "DC precharge contactor open unsuccessfully")// - .label(16, "DC main contactor inspection abnormity")// - .label(32, "DC main contactor open unsuccessfully")// - .label(64, "Output contactor close unsuccessfully")// - .label(128, "Output contactor open unsuccessfully")// - .label(256, "AC main contactor close unsuccessfully")// - .label(512, "AC main contactor open unsuccessfully")// - .label(1024, "NegContactor open unsuccessfully")// - .label(2048, "NegContactor close unsuccessfully")// - .label(4096, "NegContactor state abnormal"))), + new UnsignedWordElement(0xA400,// + //used BsmDCDC1 as prefix on each one if it is used before + new ModbusBitWrappingChannel("BmsDCDC1SuggestiveInformation1", this, this.thingState)// + .warningBit(0, WarningCharger.BsmDCDC1CurrentSamplingChannelAbnormityOnHighVoltageSide)// + .warningBit(1, WarningCharger.BsmDCDC1CurrentSamplingChannelAbnormityOnLowVoltageSide)// + .warningBit(6, WarningCharger.BmsDCDC1EEPROMParametersOverRange)// + .warningBit(7, WarningCharger.BsmDCDC1UpdateEEPROMFailed)// + .warningBit(8, WarningCharger.BsmDCDC1ReadEEPROMFailed)// + .warningBit(9, WarningCharger.BsmDCDC1CurrentSamplingChannelAbnormityBeforeInductance)// + ),// + + new UnsignedWordElement(0xA401, // + //Prefix = "BsmDCDC1" + new ModbusBitWrappingChannel("BmsDCDC1SuggestiveInformation2", this, this.thingState)// + .warningBit(0, WarningCharger.BsmDCDC1ReactorPowerDecreaseCausedByOvertemperature)// + .warningBit(1, WarningCharger.BsmDCDC1IGBTPowerDecreaseCausedByOvertemperature)// + .warningBit(2, WarningCharger.BsmDCDC1TemperatureChanel3PowerDecreaseCausedByOvertemperature)// + .warningBit(3, WarningCharger.BsmDCDC1TemperatureChanel4PowerDecreaseCausedByOvertemperature)// + .warningBit(4, WarningCharger.BsmDCDC1TemperatureChanel5PowerDecreaseCausedByOvertemperature)// + .warningBit(5, WarningCharger.BsmDCDC1TemperatureChanel6PowerDecreaseCausedByOvertemperature)// + .warningBit(6, WarningCharger.BsmDCDC1TemperatureChanel7PowerDecreaseCausedByOvertemperature)// + .warningBit(7, WarningCharger.BsmDCDC1TemperatureChanel8PowerDecreaseCausedByOvertemperature)// + .warningBit(8, WarningCharger.BsmDCDC1Fan1StopFailed)// + .warningBit(9, WarningCharger.BsmDCDC1Fan2StopFailed)// + .warningBit(10,WarningCharger.BsmDCDC1Fan3StopFailed)// + .warningBit(11,WarningCharger.BsmDCDC1Fan4StopFailed)// + .warningBit(12,WarningCharger.BsmDCDC1Fan1StartupFailed)// + .warningBit(13,WarningCharger.BsmDCDC1Fan2StartupFailed)// + .warningBit(14,WarningCharger.BsmDCDC1Fan3StartupFailed)// + .warningBit(15,WarningCharger.BsmDCDC1Fan4StartupFailed)// + ),// + new UnsignedWordElement(0xA402,// + //prefix = "BsmDCDC1" + new ModbusBitWrappingChannel("BmsDCDC1SuggestiveInformation3", this, this.thingState)// + .warningBit(0, WarningCharger.BsmDCDC1HighVoltageSideOvervoltage)// + .warningBit(1, WarningCharger.BsmDCDC1HighVoltageSideUndervoltage)// + .warningBit(2, WarningCharger.BsmDCDC1HighVoltageSideVoltageChangeUnconventionally)// + ),// + + new UnsignedWordElement(0xA403, // + //prefix = "BsmDCDC1" + new ModbusBitWrappingChannel("BmsDCDC1SuggestiveInformation4", this, this.thingState)// + .warningBit(0, WarningCharger.BmsDCDC1CurrentAbnormityBeforeDCConverterWorkOnHighVoltageSide) + .warningBit(1, WarningCharger.BmsDCDC1CurrentAbnormityBeforeDCConverterWorkOnLowVoltageSXide) + .warningBit(2, WarningCharger.BmsDCDC1InitialDutyRatioAbnormityBeforeDCConverterWork) + .warningBit(3, WarningCharger.BmsDCDC1VoltageAbnormityBeforeDCConverterWorkOnHighVoltageSide) + .warningBit(4, WarningCharger.BmsDCDC1VoltageAbnormityBeforeDCConverterWorkOnLowVoltageSide) + ),// + + new UnsignedWordElement(0xA404,// + // prefix = "BsmDCDC1" + new ModbusBitWrappingChannel("BmsDCDC1SuggestiveInformation5", this, this.thingState)// + .warningBit(0, WarningCharger.BmsDCDC1HighVoltageBreakerInspectionAbnormity)// + .warningBit(1, WarningCharger.BmsDCDC1LowVoltageBreakerInspectionAbnormity)// + .warningBit(2, WarningCharger.BmsDCDC1BsmDCDC5DCPrechargeContactorInspectionAbnormity)// + .warningBit(3, WarningCharger.BmsDCDC1DCPrechargeContactorOpenUnsuccessfully)// + .warningBit(4, WarningCharger.BmsDCDC1DCMainContactorInspectionAbnormity)// + .warningBit(5, WarningCharger.BmsDCDC1DCMainContactorOpenUnsuccessfully)// + .warningBit(6, WarningCharger.BmsDCDC1OutputContactorCloseUnsuccessfully)// + .warningBit(7, WarningCharger.BmsDCDC1OutputContactorOpenUnsuccessfully)// + .warningBit(8, WarningCharger.BmsDCDC1ACMainContactorCloseUnsuccessfully)// + .warningBit(9, WarningCharger.BmsDCDC1ACMainContactorOpenUnsuccessfully)// + .warningBit(10,WarningCharger.BmsDCDC1NegContactorOpenUnsuccessfully)// + .warningBit(11,WarningCharger.BmsDCDC1NegContactorCloseUnsuccessfully)// + .warningBit(12,WarningCharger.BmsDCDC1NegContactorStateAbnormal)// + ),// + new DummyElement(0xA405, 0xA40F), new UnsignedWordElement(0xA410, - bmsDCDC1Abnormity1 = warning.channel(new StatusBitChannel("BmsDCDC1Abnormity1", this)// - .label(1, "High voltage side of DC Converter undervoltage")// - .label(2, "High voltage side of DC Converter overvoltage")// - .label(4, "Low voltage side of DC Converter undervoltage")// - .label(8, "Low voltage side of DC Converter overvoltage")// - .label(16, "High voltage side of DC Converter overcurrent fault")// - .label(32, "Low voltage side of DC Converter overcurrent fault")// - .label(64, "DC Converter IGBT fault")// - .label(128, "DC Converter Precharge unmet"))), + // prefix = "BsmDCDC1" + new ModbusBitWrappingChannel("BmsDCDC1Abnormity1", this, this.thingState)// + .faultBit(0, FaultCharger.BmsDCDC1HighVoltageSideOfDCConverterUndervoltage)// + .faultBit(1, FaultCharger.BmsDCDC1HighVoltageSideOfDCConverterOvervoltage)// + .faultBit(2, FaultCharger.BmsDCDC1LowVoltageSideOfDCConverterUndervoltage)// + .faultBit(3, FaultCharger.BmsDCDC1LowVoltageSideOfDCConverterOvervoltage)// + .faultBit(4, FaultCharger.BmsDCDC1HighVoltageSideOfDCConverterOvercurrentFault)// + .faultBit(5, FaultCharger.BmsDCDC1LowVoltageSideOfDCConverterOvercurrentFault)// + .faultBit(6, FaultCharger.BmsDCDC1DCConverterIGBTFault)// + .faultBit(7, FaultCharger.BmsDCDC1DCConverterPrechargeUnmet)// + ),// + new UnsignedWordElement(0xA411, - bmsDCDC1Abnormity2 = warning.channel(new StatusBitChannel("BmsDCDC1Abnormity2", this)// - .label(1, "BECU communication disconnected")// - .label(2, "DC Converter communication disconnected")// - .label(4, "Current configuration over range")// - .label(8, "The battery request stop")// - .label(32, "Overcurrent relay fault")// - .label(64, "Lightning protection device fault")// - .label(128, "DC Converter priamary contactor disconnected abnormally")// - .label(512, "DC disconnected abnormally on low voltage side of DC convetor")// - .label(4096, "DC convetor EEPROM abnormity 1")// - .label(8192, "DC convetor EEPROM abnormity 1")// - .label(16384, "EDC convetor EEPROM abnormity 1"))), - new UnsignedWordElement(0xA412, - bmsDCDC1Abnormity3 = warning.channel(new StatusBitChannel("BmsDCDC1Abnormity3", this)// - .label(1, "DC Convertor general overload")// - .label(2, "DC short circuit")// - .label(4, "Peak pulse current protection")// - .label(8, "DC disconnect abnormally on high voltage side of DC convetor")// - .label(16, "Effective pulse value overhigh")// - .label(32, "DC Converte severe overload")// - .label(64, - "DC breaker disconnect abnormally on high voltage side of DC convetor")// - .label(128, - "DC breaker disconnect abnormally on low voltage side of DC convetor")// - .label(256, "DC convetor precharge contactor close failed ")// - .label(512, "DC convetor main contactor close failed")// - .label(1024, "AC contactor state abnormity of DC convetor")// - .label(2048, "DC convetor emergency stop")// - .label(4096, "DC converter charging gun disconnected")// - .label(8192, "DC current abnormity before DC convetor work")// - .label(16384, "Fuse disconnected")// - .label(32768, "DC converter hardware current or voltage fault"))), + // prefix = "BsmDCDC1" + new ModbusBitWrappingChannel("BmsDCDC1Abnormity2", this, this.thingState)// + .faultBit(0, FaultCharger.BmsDCDC1BECUCommunicationDisconnected)// + .faultBit(1, FaultCharger.BmsDCDC1DCConverterCommunicationDisconnected)// + .faultBit(2, FaultCharger.BmsDCDC1CurrentConfigurationOverRange)// + .faultBit(3, FaultCharger.BmsDCDC1TheBatteryRequestStop)// + .faultBit(5, FaultCharger.BmsDCDC1OvercurrentRelayFault)// + .faultBit(6, FaultCharger.BmsDCDC1LightningProtectionDeviceFault)// + .faultBit(7, FaultCharger.BmsDCDC1DCConverterPriamaryContactorDisconnectedAbnormally)// + .faultBit(9, FaultCharger.BmsDCDC1DCDisconnectedAbnormallyOnLowVoltageSideOfDCConvetor)// + .faultBit(12,FaultCharger.BmsDCDC1DCConvetorEEPROMAbnormity1)// + .faultBit(13,FaultCharger.BmsDCDC1DCConvetorEEPROMAbnormity1Second)// + .faultBit(14,FaultCharger.BmsDCDC1EDCConvetorEEPROMAbnormity1)// + ),// + + new UnsignedWordElement(0xA412,// + //prefix = "BsmDCDC1" + new ModbusBitWrappingChannel("BmsDCDC1Abnormity3", this, this.thingState)// + .faultBit(0, FaultCharger.BsmDCDC1DCConvertorGeneralOverload)// + .faultBit(1, FaultCharger.BsmDCDC1DCShortCircuit)// + .faultBit(2, FaultCharger.BsmDCDC1PeakPulseCurrentProtection)// + .faultBit(3, FaultCharger.BsmDCDC1DCDisconnectAbnormallyOnHighVoltageSideOfDCConvetor)// + .faultBit(4, FaultCharger.BsmDCDC1EffectivePulseValueOverhigh)// + .faultBit(5, FaultCharger.BsmDCDC1DCConverteSevereOverload)// + .faultBit(6, FaultCharger.BsmDCDC1DCBreakerDisconnectAbnormallyOnHighVoltageSideOfDCConvetor)// + .faultBit(7, FaultCharger.BsmDCDC1DCBreakerDisconnectAbnormallyOnLowVoltageSideOfDCConvetor)// + .faultBit(8, FaultCharger.BsmDCDC1DCConvetorPrechargeContactorCloseFailed)// + .faultBit(9, FaultCharger.BsmDCDC1DCConvetorMainContactorCloseFailed)// + .faultBit(10,FaultCharger.BsmDCDC1ACContactorStateAbnormityOfDCConvetor)// + .faultBit(11,FaultCharger.BsmDCDC1DCConvetorEmergencyStop)// + .faultBit(12,FaultCharger.BsmDCDC1DCConverterChargingGunDisconnected)// + .faultBit(13,FaultCharger.BsmDCDC1DCCurrentAbnormityBeforeDCConvetorWork)// + .faultBit(14,FaultCharger.BsmDCDC1FuSeDisconnected)// + .faultBit(15,FaultCharger.BsmDCDC1DCConverterHardwareCurrentOrVoltageFault)// + ),// + new UnsignedWordElement(0xA413, - bmsDCDC1Abnormity4 = warning.channel(new StatusBitChannel("BmsDCDC1Abnormity4", this)// - .label(1, "DC converter crystal oscillator circuit invalidation")// - .label(2, "DC converter reset circuit invalidation")// - .label(4, "DC converter sampling circuit invalidation")// - .label(8, "DC converter digital I/O circuit invalidation")// - .label(16, "DC converter PWM circuit invalidation")// - .label(32, "DC converter X5045 circuit invalidation")// - .label(64, "DC converter CAN circuit invalidation")// - .label(128, "DC converter software&hardware protection circuit invalidation")// - .label(256, "DC converter power circuit invalidation")// - .label(512, "DC converter CPU invalidation")// - .label(1024, "DC converter TINT0 interrupt invalidation")// - .label(2048, "DC converter ADC interrupt invalidation")// - .label(4096, "DC converter CAPITN4 interrupt invalidation")// - .label(8192, "DC converter CAPINT6 interrupt invalidation")// - .label(16384, "DC converter T3PINTinterrupt invalidation")// - .label(32768, "DC converter T4PINTinterrupt invalidation"))), + // prefix = "BsmDCDC1" + new ModbusBitWrappingChannel("BmsDCDC1Abnormity4", this, this.thingState)// + .faultBit(0, FaultCharger.BmsDCDC1DCConverterCrystalOscillatorCircuitInvalidation)// + .faultBit(1, FaultCharger.BmsDCDC1DCConverterResetCircuitInvalidation)// + .faultBit(2, FaultCharger.BmsDCDC1DCConverterSamplingCircuitInvalidation)// + .faultBit(3, FaultCharger.BmsDCDC1DCConverterDigitalIOCircuitInvalidation)// + .faultBit(4, FaultCharger.BmsDCDC1DCConverterPWMCircuitInvalidation)// + .faultBit(5, FaultCharger.BmsDCDC1DCConverterX5045CircuitInvalidation)// + .faultBit(6, FaultCharger.BmsDCDC1DCConverterCANCircuitInvalidation)// + .faultBit(7, FaultCharger.BmsDCDC1DCConverterSoftwareANDHardwareProtectionCircuitInvalidation)// + .faultBit(8, FaultCharger.BmsDCDC1DCConverterPowerCircuitInvalidation)// + .faultBit(9, FaultCharger.BmsDCDC1DCConverterCPUInvalidation)// + .faultBit(10,FaultCharger.BmsDCDC1DCConverterTINT0InterruptInvalidation)// + .faultBit(11,FaultCharger.BmsDCDC1DCConverterADCInterruptInvalidation)// + .faultBit(12,FaultCharger.BmsDCDC1DCConverterCAPITN4InterruptInvalidation)// + .faultBit(13,FaultCharger.BmsDCDC1DCConverterCAPINT6InterruptInvalidation)// + .faultBit(14,FaultCharger.BmsDCDC1DCConverterT3PINTinterruptInvalidation)// + .faultBit(15,FaultCharger.BmsDCDC1DCConverterT4PINTinterruptInvalidation)// + ),// new UnsignedWordElement(0xA414, - bmsDCDC1Abnormity5 = warning.channel(new StatusBitChannel("BmsDCDC1Abnormity5", this)// - .label(1, "DC converter PDPINTA interrupt invalidation")// - .label(2, "DC converter T1PINT interrupt invalidation")// - .label(4, "DC converter RESV interrupt invalidation")// - .label(8, "DC converter 100us task invalidation")// - .label(16, "DC converter clock invalidation")// - .label(32, "DC converter EMS memory invalidation")// - .label(64, "DC converter exterior communication invalidation")// - .label(128, "DC converter IO Interface invalidation")// - .label(256, "DC converter Input Voltage bound fault")// - .label(512, "DC converter Outter Voltage bound fault")// - .label(1024, "DC converter Output Voltage bound fault")// - .label(2048, "DC converter Induct Current bound fault")// - .label(4096, "DC converter Input Current bound fault")// - .label(8192, "DC converter Output Current bound fault"))), + // prefix = "BsmDCDC1" + new ModbusBitWrappingChannel("BmsDCDC1Abnormity5", this, this.thingState)// + .faultBit(0, FaultCharger.BmsDCDC1DCConverterPDPINTAInterruptInvalidation)// + .faultBit(1, FaultCharger.BmsDCDC1DCConverterT1PINTInterruptInvalidationSecond)// + .faultBit(2, FaultCharger.BmsDCDC1DCConverterRESVInterruptInvalidation)// + .faultBit(3, FaultCharger.BmsDCDC1DCConverter100usTaskInvalidation)// + .faultBit(4, FaultCharger.BmsDCDC1DCConverterClockInvalidation)// + .faultBit(5, FaultCharger.BmsDCDC1DCConverterEMSMemoryInvalidation)// + .faultBit(6, FaultCharger.BmsDCDC1DCConverterExteriorCommunicationInvalidation)// + .faultBit(7, FaultCharger.BmsDCDC1DCConverterIOInterfaceInvalidation)// + .faultBit(8, FaultCharger.BmsDCDC1DCConverterInputVoltageBoundFault)// + .faultBit(9, FaultCharger.BmsDCDC1DCConverterOutterVoltageBoundFault)// + .faultBit(10,FaultCharger.BmsDCDC1DCConverterOutputVoltageBoundFault)// + .faultBit(11,FaultCharger.BmsDCDC1DCConverterInductCurrentBoundFault)// + .faultBit(12,FaultCharger.BmsDCDC1DCConverterInputCurrentBoundFault)// + .faultBit(13,FaultCharger.BmsDCDC1DCConverterOutputCurrentBoundFault)// + ),// new UnsignedWordElement(0xA415, - bmsDCDC1Abnormity6 = warning.channel(new StatusBitChannel("BmsDCDC1Abnormity6", this)// - .label(1, "DC Reactor over temperature")// - .label(2, "DC IGBT over temperature")// - .label(4, "DC Converter chanel 3 over temperature")// - .label(8, "DC Converter chanel 4 over temperature")// - .label(16, "DC Converter chanel 5 over temperature")// - .label(32, "DC Converter chanel 6 over temperature")// - .label(64, "DC Converter chanel 7 over temperature")// - .label(128, "DC Converter chanel 8 over temperature")// - .label(256, "DC Reactor temperature sampling invalidation")// - .label(512, "DC IGBT temperature sampling invalidation")// - .label(1024, "DC Converter chanel 3 temperature sampling invalidation")// - .label(2048, "DC Converter chanel 4 temperature sampling invalidation")// - .label(4096, "DC Converter chanel 5 temperature sampling invalidation")// - .label(8192, "DC Converter chanel 6 temperature sampling invalidation")// - .label(16384, "DC Converter chanel 7 temperature sampling invalidation")// - .label(32768, "DC Converter chanel 8 temperature sampling invalidation"))), + // prefix = "BsmDCDC1" + new ModbusBitWrappingChannel("BmsDCDC1Abnormity6", this, this.thingState)// + .faultBit(0, FaultCharger.BmsDCDC1DCReactorOverTemperature)// + .faultBit(1, FaultCharger.BmsDCDC1DCIGBTOverTemperature)// + .faultBit(2, FaultCharger.BmsDCDC1DCConverterChanel3OverTemperature)// + .faultBit(3, FaultCharger.BmsDCDC1DCConverterChanel4OverTemperature)// + .faultBit(4, FaultCharger.BmsDCDC1DCConverterChanel5OverTemperature)// + .faultBit(5, FaultCharger.BmsDCDC1DCConverterChanel6OverTemperature)// + .faultBit(6, FaultCharger.BmsDCDC1DCConverterChanel7OverTemperature)// + .faultBit(7, FaultCharger.BmsDCDC1DCConverterChanel8OverTemperature)// + .faultBit(8, FaultCharger.BmsDCDC1DCReactorTemperatureSamplingInvalidation)// + .faultBit(9, FaultCharger.BmsDCDC1DCIGBTTemperatureSamplingInvalidation)// + .faultBit(10,FaultCharger.BmsDCDC1DCConverterChanel3TemperatureSamplingInvalidation)// + .faultBit(11,FaultCharger.BmsDCDC1DCConverterChanel4TemperatureSamplingInvalidation)// + .faultBit(12,FaultCharger.BmsDCDC1DCConverterChanel5TemperatureSamplingInvalidation)// + .faultBit(13,FaultCharger.BmsDCDC1DCConverterChanel6TemperatureSamplingInvalidation)// + .faultBit(14,FaultCharger.BmsDCDC1DCConverterChanel7TemperatureSamplingInvalidation)// + .faultBit(15,FaultCharger.BmsDCDC1DCConverterChanel8TemperatureSamplingInvalidation)// + ),// new UnsignedWordElement(0xA416, - bmsDCDC1Abnormity7 = warning.channel(new StatusBitChannel("BmsDCDC1Abnormity7", this)// - .label(32, "DC Converter inductance current sampling invalidation")// - .label(64, - "Current sampling invalidation on the low voltage sideof DC Converter")// - .label(128, - "Voltage sampling invalidation on the low voltage side of DC Converter")// - .label(256, "Insulation inspection fault")// - .label(512, "NegContactor close unsuccessly")// - .label(1024, "NegContactor cut When running"))), + // prefix = "BsmDCDC1" + new ModbusBitWrappingChannel("BmsDCDC1Abnormity7", this, this.thingState)// + .faultBit(4, FaultCharger.BmsDCDC1DCConverterInductanceCurrentSamplingInvalidation)// + .faultBit(5, FaultCharger.BmsDCDC1CurrentSamplingInvalidationOnTheLowVoltageSideOfDCConverter)// + .faultBit(6, FaultCharger.BmsDCDC1VoltageSamplingInvalidationOnTheLowVoltageSideOfDCConverter)// + .faultBit(7, FaultCharger.BmsDCDC1InsulationInspectionFault)// + .faultBit(8, FaultCharger.BmsDCDC1NegContactorCloseUnsuccessly)// + .faultBit(9, FaultCharger.BmsDCDC1NegContactorCutWhenRunning)// + ),// new DummyElement(0xA417, 0xA41F), new UnsignedWordElement(0xA420, bmsDCDC1SwitchState = new StatusBitChannel("BmsDCDC1SwitchState", this)// - .label(1, "DC precharge contactor")// - .label(2, "DC main contactor")// - .label(4, "Output contactor")// - .label(8, "Output breaker")// - .label(16, "Input breaker")// - .label(32, "AC contactor")// - .label(64, "Emergency stop button")// - .label(128, "NegContactor"))), + .label(1, "DC precharge contactor")// + .label(2, "DC main contactor")// + .label(4, "Output contactor")// + .label(8, "Output breaker")// + .label(16, "Input breaker")// + .label(32, "AC contactor")// + .label(64, "Emergency stop button")// + .label(128, "NegContactor"))), new ModbusRegisterRange(0xA430, // new SignedWordElement(0xA430, bmsDCDC1OutputVoltage = new ModbusReadLongChannel("BmsDCDC1OutputVoltage", this) - .unit("mV").multiplier(2)), + .unit("mV").multiplier(2)), new SignedWordElement(0xA431, bmsDCDC1OutputCurrent = new ModbusReadLongChannel("BmsDCDC1OutputCurrent", this) - .unit("mA").multiplier(2)), + .unit("mA").multiplier(2)), new SignedWordElement(0xA432, bmsDCDC1OutputPower = new ModbusReadLongChannel("BmsDCDC1OutputPower", this).unit("W") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0xA433, bmsDCDC1InputVoltage = new ModbusReadLongChannel("BmsDCDC1InputVoltage", this) - .unit("mV").multiplier(2)), + .unit("mV").multiplier(2)), new SignedWordElement(0xA434, bmsDCDC1InputCurrent = new ModbusReadLongChannel("BmsDCDC1InputCurrent", this) - .unit("mA").multiplier(2)), + .unit("mA").multiplier(2)), new SignedWordElement(0xA435, bmsDCDC1InputPower = new ModbusReadLongChannel("BmsDCDC1InputPower", this).unit("W") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0xA436, bmsDCDC1InputEnergy = new ModbusReadLongChannel("BmsDCDC1InputEnergy", this).unit("Wh") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0xA437, bmsDCDC1OutputEnergy = new ModbusReadLongChannel("BmsDCDC1OutputEnergy", this) - .unit("Wh").multiplier(2)), + .unit("Wh").multiplier(2)), new DummyElement(0xA438, 0xA43F), new SignedWordElement(0xA440, bmsDCDC1ReactorTemperature = new ModbusReadLongChannel("BmsDCDC1ReactorTemperature", this).unit("°C")), new SignedWordElement(0xA441, bmsDCDC1IgbtTemperature = new ModbusReadLongChannel("BmsDCDC1IgbtTemperature", this) - .unit("°C")), + .unit("°C")), new DummyElement(0xA442, 0xA44F), new UnsignedDoublewordElement(0xA450, bmsDCDC1InputTotalChargeEnergy = new ModbusReadLongChannel( "BmsDCDC1InputTotalChargeEnergy", this).unit("Wh").multiplier(2)) - .wordOrder(WordOrder.LSWMSW), + .wordOrder(WordOrder.LSWMSW), new UnsignedDoublewordElement(0xA452, bmsDCDC1InputTotalDischargeEnergy = new ModbusReadLongChannel( "BmsDCDC1InputTotalDischargeEnergy", this).unit("Wh").multiplier(2)) - .wordOrder(WordOrder.LSWMSW), + .wordOrder(WordOrder.LSWMSW), new UnsignedDoublewordElement(0xA454, bmsDCDC1OutputTotalChargeEnergy = new ModbusReadLongChannel( "BmsDCDC1OutputTotalChargeEnergy", this).unit("Wh").multiplier(2)) - .wordOrder(WordOrder.LSWMSW), + .wordOrder(WordOrder.LSWMSW), new UnsignedDoublewordElement(0xA456, bmsDCDC1OutputTotalDischargeEnergy = new ModbusReadLongChannel( "BmsDCDC1OutputTotalDischargeEnergy", this).unit("Wh") - .multiplier(2)).wordOrder(WordOrder.LSWMSW)), + .multiplier(2)).wordOrder(WordOrder.LSWMSW)), new ModbusRegisterRange(0xA600, // new UnsignedWordElement(0xA600, pvDCDCWorkState = new ModbusReadLongChannel("PvDCDCWorkState", this)// - .label(2, "Initial")// - .label(4, "Stop")// - .label(8, "Ready")// - .label(16, "Running")// - .label(32, "Fault")// - .label(64, "Debug")// - .label(128, "Locked")), + .label(2, "Initial")// + .label(4, "Stop")// + .label(8, "Ready")// + .label(16, "Running")// + .label(32, "Fault")// + .label(64, "Debug")// + .label(128, "Locked")), new UnsignedWordElement(0xA601, pvDCDCWorkMode = new ModbusReadLongChannel("PvDCDCWorkMode", this)// - .label(128, "Constant Current")// - .label(256, "Constant Voltage")// - .label(512, "Boost MPPT"))), + .label(128, "Constant Current")// + .label(256, "Constant Voltage")// + .label(512, "Boost MPPT"))), new ModbusRegisterRange(0xA700, // - new UnsignedWordElement(0xA700, - pvDCDCSuggestiveInformation1 = warning - .channel(new StatusBitChannel("PvDCDCSuggestiveInformation1", this)// - .label(1, "Current sampling channel abnormity on high voltage side")// - .label(2, "Current sampling channel abnormity on low voltage side")// - .label(64, "EEPROM parameters over range")// - .label(128, "Update EEPROM failed")// - .label(256, "Read EEPROM failed")// - .label(512, "Current sampling channel abnormity before inductance"))), - new UnsignedWordElement(0xA701, pvDCDCSuggestiveInformation2 = warning - .channel(new StatusBitChannel("PvDCDCSuggestiveInformation2", this)// - .label(1, "Reactor power decrease caused by overtemperature")// - .label(2, "IGBT power decrease caused by overtemperature")// - .label(4, "Temperature chanel3 power decrease caused by overtemperature")// - .label(8, "Temperature chanel4 power decrease caused by overtemperature")// - .label(16, "Temperature chanel5 power decrease caused by overtemperature")// - .label(32, "Temperature chanel6 power decrease caused by overtemperature")// - .label(64, "Temperature chanel7 power decrease caused by overtemperature")// - .label(128, "Temperature chanel8 power decrease caused by overtemperature")// - .label(256, "Fan 1 stop failed")// - .label(512, "Fan 2 stop failed")// - .label(1024, "Fan 3 stop failed")// - .label(2048, "Fan 4 stop failed")// - .label(4096, "Fan 1 sartup failed")// - .label(8192, "Fan 2 sartup failed")// - .label(16384, "Fan 3 sartup failed")// - .label(32768, "Fan 4 sartup failed"))), - new UnsignedWordElement(0xA702, - pvDCDCSuggestiveInformation3 = warning - .channel(new StatusBitChannel("PvDCDCSuggestiveInformation3", this)// - .label(1, "High voltage side overvoltage")// - .label(2, "High voltage side undervoltage")// - .label(4, "EEPROM parameters over range")// - .label(8, "High voltage side voltage change unconventionally"))), - new UnsignedWordElement(0xA703, pvDCDCSuggestiveInformation4 = warning - .channel(new StatusBitChannel("PvDCDCSuggestiveInformation4", this)// - .label(1, "Current abnormity before DC Converter work on high voltage side")// - .label(2, "Current abnormity before DC Converter work on low voltage side")// - .label(4, "Initial Duty Ratio abnormity before DC Converter work")// - .label(8, "Voltage abnormity before DC Converter work on high voltage side")// - .label(16, "Voltage abnormity before DC Converter work on low voltage side"))), - new UnsignedWordElement(0xA704, - pvDCDCSuggestiveInformation5 = warning - .channel(new StatusBitChannel("PvDCDCSuggestiveInformation5", this)// - .label(1, "High voltage breaker inspection abnormity")// - .label(2, "Low voltage breaker inspection abnormity")// - .label(4, "DC precharge contactor inspection abnormity")// - .label(8, "DC precharge contactor open unsuccessfully")// - .label(16, "DC main contactor inspection abnormity")// - .label(32, "DC main contactor open unsuccessfully")// - .label(64, "Output contactor close unsuccessfully")// - .label(128, "Output contactor open unsuccessfully")// - .label(256, "AC main contactor close unsuccessfully")// - .label(512, "AC main contactor open unsuccessfully")// - .label(1024, "NegContactor open unsuccessfully")// - .label(2048, "NegContactor close unsuccessfully")// - .label(4096, "NegContactor state abnormal"))), + new UnsignedWordElement(0xA700,// + // prefix = "PvDCDC " + new ModbusBitWrappingChannel("PvDCDCSuggestiveInformation1" , this, this.thingState)// + .warningBit(0, WarningCharger.PvDCDCCurrentSamplingChannelAbnormityOnHighVoltageSide)// + .warningBit(1, WarningCharger.PvDCDCCurrentSamplingChannelAbnormityOnLowVoltageSide)// + .warningBit(6, WarningCharger.PvDCDCEEPROMParametersOverRange)// + .warningBit(7, WarningCharger.PvDCDCUpdateEEPROMFailed)// + .warningBit(8, WarningCharger.PvDCDCReadEEPROMFailed)// + .warningBit(9, WarningCharger.PvDCDCCurrentSamplingChannelAbnormityBeforeInductance)// + ),// + + new UnsignedWordElement(0xA701, // + //prefix = "PvDCDC " + new ModbusBitWrappingChannel("PvDCDCSuggestiveInformation2", this, this.thingState)// + .warningBit(0, WarningCharger.PvDCDCReactorPowerDecreaseCausedByOvertemperature)// + .warningBit(1, WarningCharger.PvDCDCIGBTPowerDecreaseCausedByOvertemperature)// + .warningBit(2, WarningCharger.PvDCDCTemperatureChanel3PowerDecreaseCausedByOvertemperature)// + .warningBit(3, WarningCharger.PvDCDCTemperatureChanel4PowerDecreaseCausedByOvertemperature)// + .warningBit(4, WarningCharger.PvDCDCTemperatureChanel5PowerDecreaseCausedByOvertemperature)// + .warningBit(5, WarningCharger.PvDCDCTemperatureChanel6PowerDecreaseCausedByOvertemperature)// + .warningBit(6, WarningCharger.PvDCDCTemperatureChanel7PowerDecreaseCausedByOvertemperature)// + .warningBit(7, WarningCharger.PvDCDCTemperatureChanel8PowerDecreaseCausedByOvertemperature)// + .warningBit(8, WarningCharger.PvDCDCFan1StopFailed)// + .warningBit(9, WarningCharger.PvDCDCFan2StopFailed)// + .warningBit(10,WarningCharger.PvDCDCFan3StopFailed)// + .warningBit(11,WarningCharger.PvDCDCFan4StopFailed)// + .warningBit(12,WarningCharger.PvDCDCFan1StartupFailed)// + .warningBit(13,WarningCharger.PvDCDCFan2StartupFailed)// + .warningBit(14,WarningCharger.PvDCDCFan3StartupFailed)// + .warningBit(15,WarningCharger.PvDCDCFan4StartupFailed)// + ),// + + new UnsignedWordElement(0xA702,// + // prefix = "PvDCDC" + new ModbusBitWrappingChannel("PvDCDCSuggestiveInformation3", this, this.thingState)// + .warningBit(0, WarningCharger.PvDCDCHighVoltageSideOvervoltage)// + .warningBit(1, WarningCharger.PvDCDCHighVoltageSideUndervoltage)// + .warningBit(2, WarningCharger.PvDCDCHighVoltageSideVoltageChangeUnconventionally)// + ),// + + new UnsignedWordElement(0xA703, + // prefix = "PvDCDC" + new ModbusBitWrappingChannel("PvDCDCSuggestiveInformation4", this, this.thingState)// + .warningBit(0, WarningCharger.PvDCDCCurrentAbnormityBeforeDCConverterWorkOnHighVoltageSide) + .warningBit(1, WarningCharger.PvDCDCCurrentAbnormityBeforeDCConverterWorkOnLowVoltageSXide) + .warningBit(2, WarningCharger.PvDCDCInitialDutyRatioAbnormityBeforeDCConverterWork) + .warningBit(3, WarningCharger.PvDCDCVoltageAbnormityBeforeDCConverterWorkOnHighVoltageSide) + .warningBit(4, WarningCharger.PvDCDCVoltageAbnormityBeforeDCConverterWorkOnLowVoltageSide) + ),// + + new UnsignedWordElement(0xA704,// + // prefix = "PvDCDC" + new ModbusBitWrappingChannel("PvDCDCSuggestiveInformation5", this, this.thingState)// + .warningBit(0, WarningCharger.PvDCDCHighVoltageBreakerInspectionAbnormity)// + .warningBit(1, WarningCharger.PvDCDCLowVoltageBreakerInspectionAbnormity)// + .warningBit(2, WarningCharger.PvDCDCBsmDCDC5DCPrechargeContactorInspectionAbnormity)// + .warningBit(3, WarningCharger.PvDCDCDCPrechargeContactorOpenUnsuccessfully)// + .warningBit(4, WarningCharger.PvDCDCDCMainContactorInspectionAbnormity)// + .warningBit(5, WarningCharger.PvDCDCDCMainContactorOpenUnsuccessfully)// + .warningBit(6, WarningCharger.PvDCDCOutputContactorCloseUnsuccessfully)// + .warningBit(7, WarningCharger.PvDCDCOutputContactorOpenUnsuccessfully)// + .warningBit(8, WarningCharger.PvDCDCACMainContactorCloseUnsuccessfully)// + .warningBit(9, WarningCharger.PvDCDCACMainContactorOpenUnsuccessfully)// + .warningBit(10,WarningCharger.PvDCDCNegContactorOpenUnsuccessfully)// + .warningBit(11,WarningCharger.PvDCDCNegContactorCloseUnsuccessfully)// + .warningBit(12,WarningCharger.PvDCDCNegContactorStateAbnormal)// + ),// + new DummyElement(0xA705, 0xA70F), - new UnsignedWordElement(0xA710, - pvDCDCAbnormity1 = warning.channel(new StatusBitChannel("PvDCDCAbnormity1", this)// - .label(1, "High voltage side of DC Converter undervoltage")// - .label(2, "High voltage side of DC Converter overvoltage")// - .label(4, "Low voltage side of DC Converter undervoltage")// - .label(8, "Low voltage side of DC Converter overvoltage")// - .label(16, "High voltage side of DC Converter overcurrent fault")// - .label(32, "Low voltage side of DC Converter overcurrent fault")// - .label(64, "DC Converter IGBT fault")// - .label(128, "DC Converter Precharge unmet"))), + new UnsignedWordElement(0xA710,// + // prefix = "PvDCDC" + new ModbusBitWrappingChannel("PvDCDCAbnormity1", this, this.thingState)// + .faultBit(0, FaultCharger.PvDCDCHighVoltageSideOfDCConverterUndervoltage)// + .faultBit(1, FaultCharger.PvDCDCHighVoltageSideOfDCConverterOvervoltage)// + .faultBit(2, FaultCharger.PvDCDCLowVoltageSideOfDCConverterUndervoltage)// + .faultBit(3, FaultCharger.PvDCDCLowVoltageSideOfDCConverterOvervoltage)// + .faultBit(4, FaultCharger.PvDCDCHighVoltageSideOfDCConverterOvercurrentFault)// + .faultBit(5, FaultCharger.PvDCDCLowVoltageSideOfDCConverterOvercurrentFault)// + .faultBit(6, FaultCharger.PvDCDCDCConverterIGBTFault)// + .faultBit(7, FaultCharger.PvDCDCDCConverterPrechargeUnmet)// + ),// + new UnsignedWordElement(0xA711, - pvDCDCAbnormity2 = warning.channel(new StatusBitChannel("PvDCDCAbnormity2", this)// - .label(1, "BECU communication disconnected")// - .label(2, "DC Converter communication disconnected")// - .label(4, "Current configuration over range")// - .label(8, "The battery request stop")// - .label(32, "Overcurrent relay fault")// - .label(64, "Lightning protection device fault")// - .label(128, "DC Converter priamary contactor disconnected abnormally")// - .label(512, "DC disconnected abnormally on low voltage side of DC convetor")// - .label(4096, "DC convetor EEPROM abnormity 1")// - .label(8192, "DC convetor EEPROM abnormity 1")// - .label(16384, "EDC convetor EEPROM abnormity 1"))), - new UnsignedWordElement(0xA712, - pvDCDCAbnormity3 = warning.channel(new StatusBitChannel("PvDCDCAbnormity3", this)// - .label(1, "DC Convertor general overload")// - .label(2, "DC short circuit")// - .label(4, "Peak pulse current protection")// - .label(8, "DC disconnect abnormally on high voltage side of DC convetor")// - .label(16, "Effective pulse value overhigh")// - .label(32, "DC Converte severe overload")// - .label(64, - "DC breaker disconnect abnormally on high voltage side of DC convetor")// - .label(128, - "DC breaker disconnect abnormally on low voltage side of DC convetor")// - .label(256, "DC convetor precharge contactor close failed ")// - .label(512, "DC convetor main contactor close failed")// - .label(1024, "AC contactor state abnormity of DC convetor")// - .label(2048, "DC convetor emergency stop")// - .label(4096, "DC converter charging gun disconnected")// - .label(8192, "DC current abnormity before DC convetor work")// - .label(16384, "Fuse disconnected")// - .label(32768, "DC converter hardware current or voltage fault"))), - new UnsignedWordElement(0xA713, - pvDCDCAbnormity4 = warning.channel(new StatusBitChannel("PvDCDCAbnormity4", this)// - .label(1, "DC converter crystal oscillator circuit invalidation")// - .label(2, "DC converter reset circuit invalidation")// - .label(4, "DC converter sampling circuit invalidation")// - .label(8, "DC converter digital I/O circuit invalidation")// - .label(16, "DC converter PWM circuit invalidation")// - .label(32, "DC converter X5045 circuit invalidation")// - .label(64, "DC converter CAN circuit invalidation")// - .label(128, "DC converter software&hardware protection circuit invalidation")// - .label(256, "DC converter power circuit invalidation")// - .label(512, "DC converter CPU invalidation")// - .label(1024, "DC converter TINT0 interrupt invalidation")// - .label(2048, "DC converter ADC interrupt invalidation")// - .label(4096, "DC converter CAPITN4 interrupt invalidation")// - .label(8192, "DC converter CAPINT6 interrupt invalidation")// - .label(16384, "DC converter T3PINTinterrupt invalidation")// - .label(32768, "DC converter T4PINTinterrupt invalidation"))), + // prefix = "PvDCDC" + new ModbusBitWrappingChannel("PvDCDCAbnormity2", this, this.thingState)// + .faultBit(0, FaultCharger.PvDCDCBECUCommunicationDisconnected)// + .faultBit(1, FaultCharger.PvDCDCDCConverterCommunicationDisconnected)// + .faultBit(2, FaultCharger.PvDCDCCurrentConfigurationOverRange)// + .faultBit(3, FaultCharger.PvDCDCTheBatteryRequestStop)// + .faultBit(5, FaultCharger.PvDCDCOvercurrentRelayFault)// + .faultBit(6, FaultCharger.PvDCDCLightningProtectionDeviceFault)// + .faultBit(7, FaultCharger.PvDCDCDCConverterPriamaryContactorDisconnectedAbnormally)// + .faultBit(9, FaultCharger.PvDCDCDCDisconnectedAbnormallyOnLowVoltageSideOfDCConvetor)// + .faultBit(12,FaultCharger.PvDCDCDCConvetorEEPROMAbnormity1)// + .faultBit(13,FaultCharger.PvDCDCDCConvetorEEPROMAbnormity1Second)// + .faultBit(14,FaultCharger.PvDCDCEDCConvetorEEPROMAbnormity1)// + ),// + + new UnsignedWordElement(0xA712,// + // prefix = "PvDCDC" + new ModbusBitWrappingChannel("PvDCDCAbnormity3", this, this.thingState)// + .faultBit(0, FaultCharger.PvDCDCDCConvertorGeneralOverload)// + .faultBit(1, FaultCharger.PvDCDCDCShortCircuit)// + .faultBit(2, FaultCharger.PvDCDCPeakPulseCurrentProtection)// + .faultBit(3, FaultCharger.PvDCDCDCDisconnectAbnormallyOnHighVoltageSideOfDCConvetor)// + .faultBit(4, FaultCharger.PvDCDCEffectivePulseValueOverhigh)// + .faultBit(5, FaultCharger.PvDCDCDCConverteSevereOverload)// + .faultBit(6, FaultCharger.PvDCDCDCBreakerDisconnectAbnormallyOnHighVoltageSideOfDCConvetor)// + .faultBit(7, FaultCharger.PvDCDCDCBreakerDisconnectAbnormallyOnLowVoltageSideOfDCConvetor)// + .faultBit(8, FaultCharger.PvDCDCDCConvetorPrechargeContactorCloseFailed)// + .faultBit(9, FaultCharger.PvDCDCDCConvetorMainContactorCloseFailed)// + .faultBit(10,FaultCharger.PvDCDCACContactorStateAbnormityOfDCConvetor)// + .faultBit(11,FaultCharger.PvDCDCDCConvetorEmergencyStop)// + .faultBit(12,FaultCharger.PvDCDCDCConverterChargingGunDisconnected)// + .faultBit(13,FaultCharger.PvDCDCDCCurrentAbnormityBeforeDCConvetorWork)// + .faultBit(14,FaultCharger.PvDCDCFuSeDisconnected)// + .faultBit(15,FaultCharger.PvDCDCDCConverterHardwareCurrentOrVoltageFault)// + ),// + + new UnsignedWordElement(0xA713,// + // prefix = "PvDCDC" + new ModbusBitWrappingChannel("PvDCDCAbnormity4", this, this.thingState)// + .faultBit(0, FaultCharger.PvDCDCDCConverterCrystalOscillatorCircuitInvalidation)// + .faultBit(1, FaultCharger.PvDCDCDCConverterResetCircuitInvalidation)// + .faultBit(2, FaultCharger.PvDCDCDCConverterSamplingCircuitInvalidation)// + .faultBit(3, FaultCharger.PvDCDCDCConverterDigitalIOCircuitInvalidation)// + .faultBit(4, FaultCharger.PvDCDCDCConverterPWMCircuitInvalidation)// + .faultBit(5, FaultCharger.PvDCDCDCConverterX5045CircuitInvalidation)// + .faultBit(6, FaultCharger.PvDCDCDCConverterCANCircuitInvalidation)// + .faultBit(7, FaultCharger.PvDCDCDCConverterSoftwareANDHardwareProtectionCircuitInvalidation)// + .faultBit(8, FaultCharger.PvDCDCDCConverterPowerCircuitInvalidation)// + .faultBit(9, FaultCharger.PvDCDCDCConverterCPUInvalidation)// + .faultBit(10,FaultCharger.PvDCDCDCConverterTINT0InterruptInvalidation)// + .faultBit(11,FaultCharger.PvDCDCDCConverterADCInterruptInvalidation)// + .faultBit(12,FaultCharger.PvDCDCDCConverterCAPITN4InterruptInvalidation)// + .faultBit(13,FaultCharger.PvDCDCDCConverterCAPINT6InterruptInvalidation)// + .faultBit(14,FaultCharger.PvDCDCDCConverterT3PINTinterruptInvalidation)// + .faultBit(15,FaultCharger.PvDCDCDCConverterT4PINTinterruptInvalidation)// + ),// + new UnsignedWordElement(0xA714, - pvDCDCAbnormity5 = warning.channel(new StatusBitChannel("PvDCDCAbnormity5", this)// - .label(1, "DC converter PDPINTA interrupt invalidation")// - .label(2, "DC converter T1PINT interrupt invalidation")// - .label(4, "DC converter RESV interrupt invalidation")// - .label(8, "DC converter 100us task invalidation")// - .label(16, "DC converter clock invalidation")// - .label(32, "DC converter EMS memory invalidation")// - .label(64, "DC converter exterior communication invalidation")// - .label(128, "DC converter IO Interface invalidation")// - .label(256, "DC converter Input Voltage bound fault")// - .label(512, "DC converter Outter Voltage bound fault")// - .label(1024, "DC converter Output Voltage bound fault")// - .label(2048, "DC converter Induct Current bound fault")// - .label(4096, "DC converter Input Current bound fault")// - .label(8192, "DC converter Output Current bound fault"))), - new UnsignedWordElement(0xA715, - pvDCDCAbnormity6 = warning.channel(new StatusBitChannel("PvDCDCAbnormity6", this)// - .label(1, "DC Reactor over temperature")// - .label(2, "DC IGBT over temperature")// - .label(4, "DC Converter chanel 3 over temperature")// - .label(8, "DC Converter chanel 4 over temperature")// - .label(16, "DC Converter chanel 5 over temperature")// - .label(32, "DC Converter chanel 6 over temperature")// - .label(64, "DC Converter chanel 7 over temperature")// - .label(128, "DC Converter chanel 8 over temperature")// - .label(256, "DC Reactor temperature sampling invalidation")// - .label(512, "DC IGBT temperature sampling invalidation")// - .label(1024, "DC Converter chanel 3 temperature sampling invalidation")// - .label(2048, "DC Converter chanel 4 temperature sampling invalidation")// - .label(4096, "DC Converter chanel 5 temperature sampling invalidation")// - .label(8192, "DC Converter chanel 6 temperature sampling invalidation")// - .label(16384, "DC Converter chanel 7 temperature sampling invalidation")// - .label(32768, "DC Converter chanel 8 temperature sampling invalidation"))), - new UnsignedWordElement(0xA716, - pvDCDCAbnormity7 = warning.channel(new StatusBitChannel("PvDCDCAbnormity7", this)// - .label(32, "DC Converter inductance current sampling invalidation")// - .label(64, - "Current sampling invalidation on the low voltage sideof DC Converter")// - .label(128, - "Voltage sampling invalidation on the low voltage side of DC Converter")// - .label(256, "Insulation inspection fault")// - .label(512, "NegContactor close unsuccessly")// - .label(1024, "NegContactor cut When running"))), + // prefix = "PvDCDC" + new ModbusBitWrappingChannel("PvDCDCAbnormity5", this, this.thingState)// + .faultBit(0, FaultCharger.PvDCDCConverterPDPINTAInterruptInvalidation)// + .faultBit(1, FaultCharger.PvDCDCConverterT1PINTInterruptInvalidationSecond)// + .faultBit(2, FaultCharger.PvDCDCConverterRESVInterruptInvalidation)// + .faultBit(3, FaultCharger.PvDCDCConverter100usTaskInvalidation)// + .faultBit(4, FaultCharger.PvDCDCConverterClockInvalidation)// + .faultBit(5, FaultCharger.PvDCDCConverterEMSMemoryInvalidation)// + .faultBit(6, FaultCharger.PvDCDCConverterExteriorCommunicationInvalidation)// + .faultBit(7, FaultCharger.PvDCDCConverterIOInterfaceInvalidation)// + .faultBit(8, FaultCharger.PvDCDCConverterInputVoltageBoundFault)// + .faultBit(9, FaultCharger.PvDCDCConverterOutterVoltageBoundFault)// + .faultBit(10,FaultCharger.PvDCDCConverterOutputVoltageBoundFault)// + .faultBit(11,FaultCharger.PvDCDCConverterInductCurrentBoundFault)// + .faultBit(12,FaultCharger.PvDCDCConverterInputCurrentBoundFault)// + .faultBit(13,FaultCharger.PvDCDCConverterOutputCurrentBoundFault)// + ),// + + new UnsignedWordElement(0xA715,// + // prefix = "PvDCDC" + new ModbusBitWrappingChannel("PvDCDCAbnormity6", this, this.thingState)// + .faultBit(0, FaultCharger.PvDCDCDCReactorOverTemperature)// + .faultBit(1, FaultCharger.PvDCDCDCIGBTOverTemperature)// + .faultBit(2, FaultCharger.PvDCDCDCConverterChanel3OverTemperature)// + .faultBit(3, FaultCharger.PvDCDCDCConverterChanel4OverTemperature)// + .faultBit(4, FaultCharger.PvDCDCDCConverterChanel5OverTemperature)// + .faultBit(5, FaultCharger.PvDCDCDCConverterChanel6OverTemperature)// + .faultBit(6, FaultCharger.PvDCDCDCConverterChanel7OverTemperature)// + .faultBit(7, FaultCharger.PvDCDCDCConverterChanel8OverTemperature)// + .faultBit(8, FaultCharger.PvDCDCDCReactorTemperatureSamplingInvalidation)// + .faultBit(9, FaultCharger.PvDCDCDCIGBTTemperatureSamplingInvalidation)// + .faultBit(10,FaultCharger.PvDCDCDCConverterChanel3TemperatureSamplingInvalidation)// + .faultBit(11,FaultCharger.PvDCDCDCConverterChanel4TemperatureSamplingInvalidation)// + .faultBit(12,FaultCharger.PvDCDCDCConverterChanel5TemperatureSamplingInvalidation)// + .faultBit(13,FaultCharger.PvDCDCDCConverterChanel6TemperatureSamplingInvalidation)// + .faultBit(14,FaultCharger.PvDCDCDCConverterChanel7TemperatureSamplingInvalidation)// + .faultBit(15,FaultCharger.PvDCDCDCConverterChanel8TemperatureSamplingInvalidation)// + ),// + + new UnsignedWordElement(0xA716,// + // prefix = "PvDCDC" + new ModbusBitWrappingChannel("PvDCDCAbnormity7", this, this.thingState)// + .faultBit(4, FaultCharger.PvDCDCDCConverterInductanceCurrentSamplingInvalidation)// + .faultBit(5, FaultCharger.PvDCDCCurrentSamplingInvalidationOnTheLowVoltageSideOfDCConverter)// + .faultBit(6, FaultCharger.PvDCDCVoltageSamplingInvalidationOnTheLowVoltageSideOfDCConverter)// + .faultBit(7, FaultCharger.PvDCDCInsulationInspectionFault)// + .faultBit(8, FaultCharger.PvDCDCNegContactorCloseUnsuccessly)// + .faultBit(9, FaultCharger.PvDCDCNegContactorCutWhenRunning)// + ),// + new DummyElement(0xA717, 0xA71F), new UnsignedWordElement(0xA720, pvDCDCSwitchState = new StatusBitChannel("PvDCDCSwitchState", this)// - .label(1, "DC precharge contactor")// - .label(2, "DC main contactor")// - .label(4, "Output contactor")// - .label(8, "Output breaker")// - .label(16, "Input breaker")// - .label(32, "AC contactor")// - .label(64, "Emergency stop button")// - .label(128, "NegContactor"))), + .label(1, "DC precharge contactor")// + .label(2, "DC main contactor")// + .label(4, "Output contactor")// + .label(8, "Output breaker")// + .label(16, "Input breaker")// + .label(32, "AC contactor")// + .label(64, "Emergency stop button")// + .label(128, "NegContactor"))), new ModbusRegisterRange(0xA730, // new SignedWordElement(0xA730, pvDCDCOutputVoltage = new ModbusReadLongChannel("PvDCDCOutputVoltage", this).unit("mV") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0xA731, pvDCDCOutputCurrent = new ModbusReadLongChannel("PvDCDCOutputCurrent", this).unit("mA") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0xA732, pvDCDCOutputPower = new ModbusReadLongChannel("PvDCDCOutputPower", this).unit("W") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0xA733, pvDCDCInputVoltage = new ModbusReadLongChannel("PvDCDCInputVoltage", this).unit("mV") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0xA734, pvDCDCInputCurrent = new ModbusReadLongChannel("PvDCDCInputCurrent", this).unit("mA") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0xA735, pvDCDCInputPower = new ModbusReadLongChannel("PvDCDCInputPower", this).unit("W") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0xA736, pvDCDCInputEnergy = new ModbusReadLongChannel("PvDCDCInputEnergy", this).unit("Wh") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0xA737, pvDCDCOutputEnergy = new ModbusReadLongChannel("PvDCDCOutputEnergy", this).unit("Wh") - .multiplier(2)), + .multiplier(2)), new DummyElement(0xA738, 0xA73F), new SignedWordElement(0xA740, pvDCDCReactorTemperature = new ModbusReadLongChannel("PvDCDCReactorTemperature", this) - .unit("°C")), + .unit("°C")), new SignedWordElement(0xA741, pvDCDCIgbtTemperature = new ModbusReadLongChannel("PvDCDCIgbtTemperature", this) - .unit("°C")), + .unit("°C")), new DummyElement(0xA742, 0xA74F), new UnsignedDoublewordElement(0xA750, pvDCDCInputTotalChargeEnergy = new ModbusReadLongChannel("PvDCDCInputTotalChargeEnergy", @@ -927,254 +995,277 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { new UnsignedDoublewordElement(0xA752, pvDCDCInputTotalDischargeEnergy = new ModbusReadLongChannel( "PvDCDCInputTotalDischargeEnergy", this).unit("Wh").multiplier(2)) - .wordOrder(WordOrder.LSWMSW), + .wordOrder(WordOrder.LSWMSW), new UnsignedDoublewordElement(0xA754, pvDCDCOutputTotalChargeEnergy = new ModbusReadLongChannel( "PvDCDCOutputTotalChargeEnergy", this).unit("Wh").multiplier(2)) - .wordOrder(WordOrder.LSWMSW), + .wordOrder(WordOrder.LSWMSW), new UnsignedDoublewordElement(0xA756, pvDCDCOutputTotalDischargeEnergy = new ModbusReadLongChannel( "PvDCDCOutputTotalDischargeEnergy", this).unit("Wh") - .multiplier(2)).wordOrder(WordOrder.LSWMSW)), + .multiplier(2)).wordOrder(WordOrder.LSWMSW)), new ModbusRegisterRange(0xA900, // new UnsignedWordElement(0xA900, pvDCDC1WorkState = new ModbusReadLongChannel("PvDCDC1WorkState", this)// - .label(2, "Initial")// - .label(4, "Stop")// - .label(8, "Ready")// - .label(16, "Running")// - .label(32, "Fault")// - .label(64, "Debug")// - .label(128, "Locked")), + .label(2, "Initial")// + .label(4, "Stop")// + .label(8, "Ready")// + .label(16, "Running")// + .label(32, "Fault")// + .label(64, "Debug")// + .label(128, "Locked")), new UnsignedWordElement(0xA901, pvDCDC1WorkMode = new ModbusReadLongChannel("PvDCDC1WorkMode", this)// - .label(128, "Constant Current")// - .label(256, "Constant Voltage")// - .label(512, "Boost MPPT"))), + .label(128, "Constant Current")// + .label(256, "Constant Voltage")// + .label(512, "Boost MPPT"))), new ModbusRegisterRange(0xAA00, // - new UnsignedWordElement(0xAA00, - pvDCDC1SuggestiveInformation1 = warning - .channel(new StatusBitChannel("PvDCDC1SuggestiveInformation1", this)// - .label(1, "Current sampling channel abnormity on high voltage side")// - .label(2, "Current sampling channel abnormity on low voltage side")// - .label(64, "EEPROM parameters over range")// - .label(128, "Update EEPROM failed")// - .label(256, "Read EEPROM failed")// - .label(512, "Current sampling channel abnormity before inductance"))), - new UnsignedWordElement(0xAA01, pvDCDC1SuggestiveInformation2 = warning - .channel(new StatusBitChannel("PvDCDC1SuggestiveInformation2", this)// - .label(1, "Reactor power decrease caused by overtemperature")// - .label(2, "IGBT power decrease caused by overtemperature")// - .label(4, "Temperature chanel3 power decrease caused by overtemperature")// - .label(8, "Temperature chanel4 power decrease caused by overtemperature")// - .label(16, "Temperature chanel5 power decrease caused by overtemperature")// - .label(32, "Temperature chanel6 power decrease caused by overtemperature")// - .label(64, "Temperature chanel7 power decrease caused by overtemperature")// - .label(128, "Temperature chanel8 power decrease caused by overtemperature")// - .label(256, "Fan 1 stop failed")// - .label(512, "Fan 2 stop failed")// - .label(1024, "Fan 3 stop failed")// - .label(2048, "Fan 4 stop failed")// - .label(4096, "Fan 1 sartup failed")// - .label(8192, "Fan 2 sartup failed")// - .label(16384, "Fan 3 sartup failed")// - .label(32768, "Fan 4 sartup failed"))), - new UnsignedWordElement(0xAA02, - pvDCDC1SuggestiveInformation3 = warning - .channel(new StatusBitChannel("PvDCDC1SuggestiveInformation3", this)// - .label(1, "High voltage side overvoltage")// - .label(2, "High voltage side undervoltage")// - .label(4, "EEPROM parameters over range")// - .label(8, "High voltage side voltage change unconventionally"))), - new UnsignedWordElement(0xAA03, pvDCDC1SuggestiveInformation4 = warning - .channel(new StatusBitChannel("PvDCDC1SuggestiveInformation4", this)// - .label(1, "Current abnormity before DC Converter work on high voltage side")// - .label(2, "Current abnormity before DC Converter work on low voltage side")// - .label(4, "Initial Duty Ratio abnormity before DC Converter work")// - .label(8, "Voltage abnormity before DC Converter work on high voltage side")// - .label(16, "Voltage abnormity before DC Converter work on low voltage side"))), + new UnsignedWordElement(0xAA00,// + // Prefix = "PvDCDC1 " + new ModbusBitWrappingChannel("PvDCDC1SuggestiveInformation1", this, this.thingState)// + .warningBit(0, WarningCharger.PvDCDC1CurrentSamplingChannelAbnormityOnHighVoltageSide)// + .warningBit(1, WarningCharger.PvDCDC1CurrentSamplingChannelAbnormityOnLowVoltageSide)// + .warningBit(6, WarningCharger.PvDCDC1EEPROMParametersOverRange)// + .warningBit(7, WarningCharger.PvDCDC1UpdateEEPROMFailed)// + .warningBit(8, WarningCharger.PvDCDC1ReadEEPROMFailed)// + .warningBit(9, WarningCharger.PvDCDC1CurrentSamplingChannelAbnormityBeforeInductance)// + ),// + + new UnsignedWordElement(0xAA01, // + // Prefix = "PvDCDC1" + new ModbusBitWrappingChannel("PvDCDC1SuggestiveInformation2", this, this.thingState)// + .warningBit(0, WarningCharger.PvDCDC1ReactorPowerDecreaseCausedByOvertemperature)// + .warningBit(1, WarningCharger.PvDCDC1IGBTPowerDecreaseCausedByOvertemperature)// + .warningBit(2, WarningCharger.PvDCDC1TemperatureChanel3PowerDecreaseCausedByOvertemperature)// + .warningBit(3, WarningCharger.PvDCDC1TemperatureChanel4PowerDecreaseCausedByOvertemperature)// + .warningBit(4, WarningCharger.PvDCDC1TemperatureChanel5PowerDecreaseCausedByOvertemperature)// + .warningBit(5, WarningCharger.PvDCDC1TemperatureChanel6PowerDecreaseCausedByOvertemperature)// + .warningBit(6, WarningCharger.PvDCDC1TemperatureChanel7PowerDecreaseCausedByOvertemperature)// + .warningBit(7, WarningCharger.PvDCDC1TemperatureChanel8PowerDecreaseCausedByOvertemperature)// + .warningBit(8, WarningCharger.PvDCDC1Fan1StopFailed)// + .warningBit(9, WarningCharger.PvDCDC1Fan2StopFailed)// + .warningBit(10,WarningCharger.PvDCDC1Fan3StopFailed)// + .warningBit(11,WarningCharger.PvDCDC1Fan4StopFailed)// + .warningBit(12,WarningCharger.PvDCDC1Fan1StartupFailed)// + .warningBit(13,WarningCharger.PvDCDC1Fan2StartupFailed)// + .warningBit(14,WarningCharger.PvDCDC1Fan3StartupFailed)// + .warningBit(15,WarningCharger.PvDCDC1Fan4StartupFailed)// + ),// + + new UnsignedWordElement(0xAA02,// + // prefix = "PvDCDC1" + new ModbusBitWrappingChannel("PvDCDC1SuggestiveInformation3", this, this.thingState)// + .warningBit(0, WarningCharger.PvDCDC1HighVoltageSideOvervoltage)// + .warningBit(1, WarningCharger.PvDCDC1HighVoltageSideUndervoltage)// + .warningBit(2, WarningCharger.PvDCDC1HighVoltageSideVoltageChangeUnconventionally)// + ),// + + new UnsignedWordElement(0xAA03,// + //prefix = "PvDCDC1" + new ModbusBitWrappingChannel("PvDCDC1SuggestiveInformation4", this, this.thingState)// + .warningBit(0, WarningCharger.PvDCDC1CurrentAbnormityBeforeDCConverterWorkOnHighVoltageSide) + .warningBit(1, WarningCharger.PvDCDC1CurrentAbnormityBeforeDCConverterWorkOnLowVoltageSXide) + .warningBit(2, WarningCharger.PvDCDC1InitialDutyRatioAbnormityBeforeDCConverterWork) + .warningBit(3, WarningCharger.PvDCDC1VoltageAbnormityBeforeDCConverterWorkOnHighVoltageSide) + .warningBit(4, WarningCharger.PvDCDC1VoltageAbnormityBeforeDCConverterWorkOnLowVoltageSide) + ),// + new UnsignedWordElement(0xAA04, - pvDCDC1SuggestiveInformation5 = warning - .channel(new StatusBitChannel("PvDCDC1SuggestiveInformation5", this)// - .label(1, "High voltage breaker inspection abnormity")// - .label(2, "Low voltage breaker inspection abnormity")// - .label(4, "DC precharge contactor inspection abnormity")// - .label(8, "DC precharge contactor open unsuccessfully")// - .label(16, "DC main contactor inspection abnormity")// - .label(32, "DC main contactor open unsuccessfully")// - .label(64, "Output contactor close unsuccessfully")// - .label(128, "Output contactor open unsuccessfully")// - .label(256, "AC main contactor close unsuccessfully")// - .label(512, "AC main contactor open unsuccessfully")// - .label(1024, "NegContactor open unsuccessfully")// - .label(2048, "NegContactor close unsuccessfully")// - .label(4096, "NegContactor state abnormal"))), + //prefix = "PvDCDC1" + new ModbusBitWrappingChannel("PvDCDC1SuggestiveInformation5", this, this.thingState)// + .warningBit(0, WarningCharger.PvDCDC1HighVoltageBreakerInspectionAbnormity)// + .warningBit(1, WarningCharger.PvDCDC1LowVoltageBreakerInspectionAbnormity)// + .warningBit(2, WarningCharger.PvDCDC1BsmDCDC5DCPrechargeContactorInspectionAbnormity)// + .warningBit(3, WarningCharger.PvDCDC1DCPrechargeContactorOpenUnsuccessfully)// + .warningBit(4, WarningCharger.PvDCDC1DCMainContactorInspectionAbnormity)// + .warningBit(5, WarningCharger.PvDCDC1DCMainContactorOpenUnsuccessfully)// + .warningBit(6, WarningCharger.PvDCDC1OutputContactorCloseUnsuccessfully)// + .warningBit(7, WarningCharger.PvDCDC1OutputContactorOpenUnsuccessfully)// + .warningBit(8, WarningCharger.PvDCDC1ACMainContactorCloseUnsuccessfully)// + .warningBit(9, WarningCharger.PvDCDC1ACMainContactorOpenUnsuccessfully)// + .warningBit(10,WarningCharger.PvDCDC1NegContactorOpenUnsuccessfully)// + .warningBit(11,WarningCharger.PvDCDC1NegContactorCloseUnsuccessfully)// + .warningBit(12,WarningCharger.PvDCDC1NegContactorStateAbnormal)// + ),// + new DummyElement(0xAA05, 0xAA0F), - new UnsignedWordElement(0xAA10, - pvDCDC1Abnormity1 = warning.channel(new StatusBitChannel("PvDCDC1Abnormity1", this)// - .label(1, "High voltage side of DC Converter undervoltage")// - .label(2, "High voltage side of DC Converter overvoltage")// - .label(4, "Low voltage side of DC Converter undervoltage")// - .label(8, "Low voltage side of DC Converter overvoltage")// - .label(16, "High voltage side of DC Converter overcurrent fault")// - .label(32, "Low voltage side of DC Converter overcurrent fault")// - .label(64, "DC Converter IGBT fault")// - .label(128, "DC Converter Precharge unmet"))), - new UnsignedWordElement(0xAA11, - pvDCDC1Abnormity2 = warning.channel(new StatusBitChannel("PvDCDC1Abnormity2", this)// - .label(1, "BECU communication disconnected")// - .label(2, "DC Converter communication disconnected")// - .label(4, "Current configuration over range")// - .label(8, "The battery request stop")// - .label(32, "Overcurrent relay fault")// - .label(64, "Lightning protection device fault")// - .label(128, "DC Converter priamary contactor disconnected abnormally")// - .label(512, "DC disconnected abnormally on low voltage side of DC convetor")// - .label(4096, "DC convetor EEPROM abnormity 1")// - .label(8192, "DC convetor EEPROM abnormity 1")// - .label(16384, "EDC convetor EEPROM abnormity 1"))), + new UnsignedWordElement(0xAA10,// + // prefix = "PvDCDC1" + new ModbusBitWrappingChannel("PvDCDC1Abnormity1", this, this.thingState)// + .faultBit(0, FaultCharger.PvDCDC1HighVoltageSideOfDCConverterUndervoltage)// + .faultBit(1, FaultCharger.PvDCDC1HighVoltageSideOfDCConverterOvervoltage)// + .faultBit(2, FaultCharger.PvDCDC1LowVoltageSideOfDCConverterUndervoltage)// + .faultBit(3, FaultCharger.PvDCDC1LowVoltageSideOfDCConverterOvervoltage)// + .faultBit(4, FaultCharger.PvDCDC1HighVoltageSideOfDCConverterOvercurrentFault)// + .faultBit(5, FaultCharger.PvDCDC1LowVoltageSideOfDCConverterOvercurrentFault)// + .faultBit(6, FaultCharger.PvDCDC1DCConverterIGBTFault)// + .faultBit(7, FaultCharger.PvDCDC1DCConverterPrechargeUnmet)// + ),// + + new UnsignedWordElement(0xAA11,// + // prefix = "PvDCDC1" + new ModbusBitWrappingChannel("PvDCDC1Abnormity2", this, this.thingState)// + .faultBit(0, FaultCharger.PvDCDC1BECUCommunicationDisconnected)// + .faultBit(1, FaultCharger.PvDCDC1DCConverterCommunicationDisconnected)// + .faultBit(2, FaultCharger.PvDCDC1CurrentConfigurationOverRange)// + .faultBit(3, FaultCharger.PvDCDC1TheBatteryRequestStop)// + .faultBit(5, FaultCharger.PvDCDC1OvercurrentRelayFault)// + .faultBit(6, FaultCharger.PvDCDC1LightningProtectionDeviceFault)// + .faultBit(7, FaultCharger.PvDCDC1DCConverterPriamaryContactorDisconnectedAbnormally)// + .faultBit(9, FaultCharger.PvDCDC1DCDisconnectedAbnormallyOnLowVoltageSideOfDCConvetor)// + .faultBit(12,FaultCharger.PvDCDC1DCConvetorEEPROMAbnormity1)// + .faultBit(13,FaultCharger.PvDCDC1DCConvetorEEPROMAbnormity1Second)// + .faultBit(14,FaultCharger.PvDCDC1EDCConvetorEEPROMAbnormity1)// + ),// + new UnsignedWordElement(0xAA12, - pvDCDC1Abnormity3 = warning.channel(new StatusBitChannel("PvDCDC1Abnormity3", this)// - .label(1, "DC Convertor general overload")// - .label(2, "DC short circuit")// - .label(4, "Peak pulse current protection")// - .label(8, "DC disconnect abnormally on high voltage side of DC convetor")// - .label(16, "Effective pulse value overhigh")// - .label(32, "DC Converte severe overload")// - .label(64, - "DC breaker disconnect abnormally on high voltage side of DC convetor")// - .label(128, - "DC breaker disconnect abnormally on low voltage side of DC convetor")// - .label(256, "DC convetor precharge contactor close failed ")// - .label(512, "DC convetor main contactor close failed")// - .label(1024, "AC contactor state abnormity of DC convetor")// - .label(2048, "DC convetor emergency stop")// - .label(4096, "DC converter charging gun disconnected")// - .label(8192, "DC current abnormity before DC convetor work")// - .label(16384, "Fuse disconnected")// - .label(32768, "DC converter hardware current or voltage fault"))), + // prefix = "PvDCDC1" + new ModbusBitWrappingChannel("PvDCDC1Abnormity3", this, this.thingState)// + .faultBit(0, FaultCharger.PvDCDC1DCConvertorGeneralOverload)// + .faultBit(1, FaultCharger.PvDCDC1DCShortCircuit)// + .faultBit(2, FaultCharger.PvDCDC1PeakPulseCurrentProtection)// + .faultBit(3, FaultCharger.PvDCDC1DCDisconnectAbnormallyOnHighVoltageSideOfDCConvetor)// + .faultBit(4, FaultCharger.PvDCDC1EffectivePulseValueOverhigh)// + .faultBit(5, FaultCharger.PvDCDC1DCConverteSevereOverload)// + .faultBit(6, FaultCharger.PvDCDC1DCBreakerDisconnectAbnormallyOnHighVoltageSideOfDCConvetor)// + .faultBit(7, FaultCharger.PvDCDC1DCBreakerDisconnectAbnormallyOnLowVoltageSideOfDCConvetor)// + .faultBit(8, FaultCharger.PvDCDC1DCConvetorPrechargeContactorCloseFailed)// + .faultBit(9, FaultCharger.PvDCDC1DCConvetorMainContactorCloseFailed)// + .faultBit(10,FaultCharger.PvDCDC1ACContactorStateAbnormityOfDCConvetor)// + .faultBit(11,FaultCharger.PvDCDC1DCConvetorEmergencyStop)// + .faultBit(12,FaultCharger.PvDCDC1DCConverterChargingGunDisconnected)// + .faultBit(13,FaultCharger.PvDCDC1DCCurrentAbnormityBeforeDCConvetorWork)// + .faultBit(14,FaultCharger.PvDCDC1FuSeDisconnected)// + .faultBit(15,FaultCharger.PvDCDC1DCConverterHardwareCurrentOrVoltageFault)// + ),// new UnsignedWordElement(0xAA13, - pvDCDC1Abnormity4 = warning.channel(new StatusBitChannel("PvDCDC1Abnormity4", this)// - .label(1, "DC converter crystal oscillator circuit invalidation")// - .label(2, "DC converter reset circuit invalidation")// - .label(4, "DC converter sampling circuit invalidation")// - .label(8, "DC converter digital I/O circuit invalidation")// - .label(16, "DC converter PWM circuit invalidation")// - .label(32, "DC converter X5045 circuit invalidation")// - .label(64, "DC converter CAN circuit invalidation")// - .label(128, "DC converter software&hardware protection circuit invalidation")// - .label(256, "DC converter power circuit invalidation")// - .label(512, "DC converter CPU invalidation")// - .label(1024, "DC converter TINT0 interrupt invalidation")// - .label(2048, "DC converter ADC interrupt invalidation")// - .label(4096, "DC converter CAPITN4 interrupt invalidation")// - .label(8192, "DC converter CAPINT6 interrupt invalidation")// - .label(16384, "DC converter T3PINTinterrupt invalidation")// - .label(32768, "DC converter T4PINTinterrupt invalidation"))), + // prefix = "PvDCDC1" + new ModbusBitWrappingChannel("PvDCDC1Abnormity4", this, this.thingState)// + .faultBit(0, FaultCharger.PvDCDC1DCConverterCrystalOscillatorCircuitInvalidation)// + .faultBit(1, FaultCharger.PvDCDC1DCConverterResetCircuitInvalidation)// + .faultBit(2, FaultCharger.PvDCDC1DCConverterSamplingCircuitInvalidation)// + .faultBit(3, FaultCharger.PvDCDC1DCConverterDigitalIOCircuitInvalidation)// + .faultBit(4, FaultCharger.PvDCDC1DCConverterPWMCircuitInvalidation)// + .faultBit(5, FaultCharger.PvDCDC1DCConverterX5045CircuitInvalidation)// + .faultBit(6, FaultCharger.PvDCDC1DCConverterCANCircuitInvalidation)// + .faultBit(7, FaultCharger.PvDCDC1DCConverterSoftwareANDHardwareProtectionCircuitInvalidation)// + .faultBit(8, FaultCharger.PvDCDC1DCConverterPowerCircuitInvalidation)// + .faultBit(9, FaultCharger.PvDCDC1DCConverterCPUInvalidation)// + .faultBit(10,FaultCharger.PvDCDC1DCConverterTINT0InterruptInvalidation)// + .faultBit(11,FaultCharger.PvDCDC1DCConverterADCInterruptInvalidation)// + .faultBit(12,FaultCharger.PvDCDC1DCConverterCAPITN4InterruptInvalidation)// + .faultBit(13,FaultCharger.PvDCDC1DCConverterCAPINT6InterruptInvalidation)// + .faultBit(14,FaultCharger.PvDCDC1DCConverterT3PINTinterruptInvalidation)// + .faultBit(15,FaultCharger.PvDCDC1DCConverterT4PINTinterruptInvalidation)// + ),// new UnsignedWordElement(0xAA14, - pvDCDC1Abnormity5 = warning.channel(new StatusBitChannel("PvDCDC1Abnormity5", this)// - .label(1, "DC converter PDPINTA interrupt invalidation")// - .label(2, "DC converter T1PINT interrupt invalidation")// - .label(4, "DC converter RESV interrupt invalidation")// - .label(8, "DC converter 100us task invalidation")// - .label(16, "DC converter clock invalidation")// - .label(32, "DC converter EMS memory invalidation")// - .label(64, "DC converter exterior communication invalidation")// - .label(128, "DC converter IO Interface invalidation")// - .label(256, "DC converter Input Voltage bound fault")// - .label(512, "DC converter Outter Voltage bound fault")// - .label(1024, "DC converter Output Voltage bound fault")// - .label(2048, "DC converter Induct Current bound fault")// - .label(4096, "DC converter Input Current bound fault")// - .label(8192, "DC converter Output Current bound fault"))), + // prefix = "PvDCDC1" + new ModbusBitWrappingChannel("PvDCDC1Abnormity5", this, this.thingState)// + .faultBit(0, FaultCharger.PvDCDC1DCConverterPDPINTAInterruptInvalidation)// + .faultBit(1, FaultCharger.PvDCDC1DCConverterT1PINTInterruptInvalidationSecond)// + .faultBit(2, FaultCharger.PvDCDC1DCConverterRESVInterruptInvalidation)// + .faultBit(3, FaultCharger.PvDCDC1DCConverter100usTaskInvalidation)// + .faultBit(4, FaultCharger.PvDCDC1DCConverterClockInvalidation)// + .faultBit(5, FaultCharger.PvDCDC1DCConverterEMSMemoryInvalidation)// + .faultBit(6, FaultCharger.PvDCDC1DCConverterExteriorCommunicationInvalidation)// + .faultBit(7, FaultCharger.PvDCDC1DCConverterIOInterfaceInvalidation)// + .faultBit(8, FaultCharger.PvDCDC1DCConverterInputVoltageBoundFault)// + .faultBit(9, FaultCharger.PvDCDC1DCConverterOutterVoltageBoundFault)// + .faultBit(10,FaultCharger.PvDCDC1DCConverterOutputVoltageBoundFault)// + .faultBit(11,FaultCharger.PvDCDC1DCConverterInductCurrentBoundFault)// + .faultBit(12,FaultCharger.PvDCDC1DCConverterInputCurrentBoundFault)// + .faultBit(13,FaultCharger.PvDCDC1DCConverterOutputCurrentBoundFault)// + ),// new UnsignedWordElement(0xAA15, - pvDCDC1Abnormity6 = warning.channel(new StatusBitChannel("PvDCDC1Abnormity6", this)// - .label(1, "DC Reactor over temperature")// - .label(2, "DC IGBT over temperature")// - .label(4, "DC Converter chanel 3 over temperature")// - .label(8, "DC Converter chanel 4 over temperature")// - .label(16, "DC Converter chanel 5 over temperature")// - .label(32, "DC Converter chanel 6 over temperature")// - .label(64, "DC Converter chanel 7 over temperature")// - .label(128, "DC Converter chanel 8 over temperature")// - .label(256, "DC Reactor temperature sampling invalidation")// - .label(512, "DC IGBT temperature sampling invalidation")// - .label(1024, "DC Converter chanel 3 temperature sampling invalidation")// - .label(2048, "DC Converter chanel 4 temperature sampling invalidation")// - .label(4096, "DC Converter chanel 5 temperature sampling invalidation")// - .label(8192, "DC Converter chanel 6 temperature sampling invalidation")// - .label(16384, "DC Converter chanel 7 temperature sampling invalidation")// - .label(32768, "DC Converter chanel 8 temperature sampling invalidation"))), + //prefix = "PvDCDC1" + new ModbusBitWrappingChannel("PvDCDC1Abnormity6", this, this.thingState)// + .faultBit(0, FaultCharger.PvDCDC1DCReactorOverTemperature)// + .faultBit(1, FaultCharger.PvDCDC1DCIGBTOverTemperature)// + .faultBit(2, FaultCharger.PvDCDC1DCConverterChanel3OverTemperature)// + .faultBit(3, FaultCharger.PvDCDC1DCConverterChanel4OverTemperature)// + .faultBit(4, FaultCharger.PvDCDC1DCConverterChanel5OverTemperature)// + .faultBit(5, FaultCharger.PvDCDC1DCConverterChanel6OverTemperature)// + .faultBit(6, FaultCharger.PvDCDC1DCConverterChanel7OverTemperature)// + .faultBit(7, FaultCharger.PvDCDC1DCConverterChanel8OverTemperature)// + .faultBit(8, FaultCharger.PvDCDC1DCReactorTemperatureSamplingInvalidation)// + .faultBit(9, FaultCharger.PvDCDC1DCIGBTTemperatureSamplingInvalidation)// + .faultBit(10,FaultCharger.PvDCDC1DCConverterChanel3TemperatureSamplingInvalidation)// + .faultBit(11,FaultCharger.PvDCDC1DCConverterChanel4TemperatureSamplingInvalidation)// + .faultBit(12,FaultCharger.PvDCDC1DCConverterChanel5TemperatureSamplingInvalidation)// + .faultBit(13,FaultCharger.PvDCDC1DCConverterChanel6TemperatureSamplingInvalidation)// + .faultBit(14,FaultCharger.PvDCDC1DCConverterChanel7TemperatureSamplingInvalidation)// + .faultBit(15,FaultCharger.PvDCDC1DCConverterChanel8TemperatureSamplingInvalidation)// + ),// new UnsignedWordElement(0xAA16, - pvDCDC1Abnormity7 = warning.channel(new StatusBitChannel("PvDCDC1Abnormity7", this)// - .label(32, "DC Converter inductance current sampling invalidation")// - .label(64, - "Current sampling invalidation on the low voltage sideof DC Converter")// - .label(128, - "Voltage sampling invalidation on the low voltage side of DC Converter")// - .label(256, "Insulation inspection fault")// - .label(512, "NegContactor close unsuccessly")// - .label(1024, "NegContactor cut When running"))), + // prefix = "PvDCDC1" + new ModbusBitWrappingChannel("PvDCDC1Abnormity7", this, this.thingState)// + .faultBit(4, FaultCharger.PvDCDC1DCConverterInductanceCurrentSamplingInvalidation)// + .faultBit(5, FaultCharger.PvDCDC1CurrentSamplingInvalidationOnTheLowVoltageSideOfDCConverter)// + .faultBit(6, FaultCharger.PvDCDC1VoltageSamplingInvalidationOnTheLowVoltageSideOfDCConverter)// + .faultBit(7, FaultCharger.PvDCDC1InsulationInspectionFault)// + .faultBit(8, FaultCharger.PvDCDC1NegContactorCloseUnsuccessly)// + .faultBit(9, FaultCharger.PvDCDC1NegContactorCutWhenRunning)// + ),// new DummyElement(0xAA17, 0xAA1F), new UnsignedWordElement(0xAA20, pvDCDC1SwitchState = new StatusBitChannel("PvDCDC1SwitchState", this)// - .label(1, "DC precharge contactor")// - .label(2, "DC main contactor")// - .label(4, "Output contactor")// - .label(8, "Output breaker")// - .label(16, "Input breaker")// - .label(32, "AC contactor")// - .label(64, "Emergency stop button")// - .label(128, "NegContactor"))), + .label(1, "DC precharge contactor")// + .label(2, "DC main contactor")// + .label(4, "Output contactor")// + .label(8, "Output breaker")// + .label(16, "Input breaker")// + .label(32, "AC contactor")// + .label(64, "Emergency stop button")// + .label(128, "NegContactor"))), new ModbusRegisterRange(0xAA30, // new SignedWordElement(0xAA30, pvDCDC1OutputVoltage = new ModbusReadLongChannel("PvDCDC1OutputVoltage", this) - .unit("mV").multiplier(2)), + .unit("mV").multiplier(2)), new SignedWordElement(0xAA31, pvDCDC1OutputCurrent = new ModbusReadLongChannel("PvDCDC1OutputCurrent", this) - .unit("mA").multiplier(2)), + .unit("mA").multiplier(2)), new SignedWordElement(0xAA32, pvDCDC1OutputPower = new ModbusReadLongChannel("PvDCDC1OutputPower", this).unit("W") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0xAA33, pvDCDC1InputVoltage = new ModbusReadLongChannel("PvDCDC1InputVoltage", this).unit("mV") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0xAA34, pvDCDC1InputCurrent = new ModbusReadLongChannel("PvDCDC1InputCurrent", this).unit("mA") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0xAA35, pvDCDC1InputPower = new ModbusReadLongChannel("PvDCDC1InputPower", this).unit("W") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0xAA36, pvDCDC1InputEnergy = new ModbusReadLongChannel("PvDCDC1InputEnergy", this).unit("Wh") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0xAA37, pvDCDC1OutputEnergy = new ModbusReadLongChannel("PvDCDC1OutputEnergy", this).unit("Wh") - .multiplier(2)), + .multiplier(2)), new DummyElement(0xAA38, 0xAA3F), new SignedWordElement(0xAA40, pvDCDC1ReactorTemperature = new ModbusReadLongChannel("PvDCDC1ReactorTemperature", this) - .unit("°C")), + .unit("°C")), new SignedWordElement(0xAA41, pvDCDC1IgbtTemperature = new ModbusReadLongChannel("PvDCDC1IgbtTemperature", this) - .unit("°C")), + .unit("°C")), new DummyElement(0xAA42, 0xAA4F), new UnsignedDoublewordElement(0xAA50, pvDCDC1InputTotalChargeEnergy = new ModbusReadLongChannel( "PvDCDC1InputTotalChargeEnergy", this).unit("Wh").multiplier(2)) - .wordOrder(WordOrder.LSWMSW), + .wordOrder(WordOrder.LSWMSW), new UnsignedDoublewordElement(0xAA52, pvDCDC1InputTotalDischargeEnergy = new ModbusReadLongChannel( "PvDCDC1InputTotalDischargeEnergy", this).unit("Wh").multiplier(2)) - .wordOrder(WordOrder.LSWMSW), + .wordOrder(WordOrder.LSWMSW), new UnsignedDoublewordElement(0xAA54, pvDCDC1OutputTotalChargeEnergy = new ModbusReadLongChannel( "PvDCDC1OutputTotalChargeEnergy", this).unit("Wh").multiplier(2)) - .wordOrder(WordOrder.LSWMSW), + .wordOrder(WordOrder.LSWMSW), new UnsignedDoublewordElement(0xAA56, pvDCDC1OutputTotalDischargeEnergy = new ModbusReadLongChannel( "PvDCDC1OutputTotalDischargeEnergy", this).unit("Wh").multiplier(2)) - .wordOrder(WordOrder.LSWMSW))); + .wordOrder(WordOrder.LSWMSW))); actualPower = new FunctionalReadChannel("ActualPower", this, (channels) -> { long erg = 0; try { @@ -1222,4 +1313,10 @@ public ReadChannel getInputVoltage() { return inputVoltage; } + @Override + public ThingStateChannels getStateChannel() { + // TODO Auto-generated method stub + return thingState; + } + } diff --git a/edge/src/io/openems/impl/device/commercial/FeneconCommercialDC.java b/edge/src/io/openems/impl/device/commercial/FeneconCommercialDC.java index d2116529678..aeb8d21aeb5 100644 --- a/edge/src/io/openems/impl/device/commercial/FeneconCommercialDC.java +++ b/edge/src/io/openems/impl/device/commercial/FeneconCommercialDC.java @@ -45,10 +45,10 @@ public FeneconCommercialDC(Bridge parent) throws OpenemsException { * Config */ @ChannelInfo(title = "Ess", description = "Sets the Ess nature.", type = FeneconCommercialEss.class) - public final ConfigChannel ess = new ConfigChannel("ess", this); + public final ConfigChannel ess = new ConfigChannel("ess", this).addChangeListener(this); @ChannelInfo(title = "Charger", description = "Sets the inverter nature.", type = FeneconCommercialCharger.class) - public final ConfigChannel charger = new ConfigChannel<>("charger", this); + public final ConfigChannel charger = new ConfigChannel("charger", this).addChangeListener(this); /* * Methods diff --git a/edge/src/io/openems/impl/device/commercial/FeneconCommercialEss.java b/edge/src/io/openems/impl/device/commercial/FeneconCommercialEss.java index 3d0162c6659..9fe7fca9f18 100644 --- a/edge/src/io/openems/impl/device/commercial/FeneconCommercialEss.java +++ b/edge/src/io/openems/impl/device/commercial/FeneconCommercialEss.java @@ -24,11 +24,12 @@ import io.openems.api.channel.ReadChannel; import io.openems.api.channel.StaticValueChannel; import io.openems.api.channel.StatusBitChannel; -import io.openems.api.channel.StatusBitChannels; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.ess.SymmetricEssNature; import io.openems.api.doc.ThingInfo; import io.openems.api.exception.ConfigException; +import io.openems.impl.protocol.modbus.ModbusBitWrappingChannel; import io.openems.impl.protocol.modbus.ModbusDeviceNature; import io.openems.impl.protocol.modbus.ModbusReadLongChannel; import io.openems.impl.protocol.modbus.ModbusWriteLongChannel; @@ -44,6 +45,8 @@ @ThingInfo(title = "FENECON Commercial ESS") public class FeneconCommercialEss extends ModbusDeviceNature implements SymmetricEssNature { + private ThingStateChannels thingState; + /* * Constructors */ @@ -55,6 +58,7 @@ public FeneconCommercialEss(String thingId, Device parent) throws ConfigExceptio chargeSoc.updateValue((Integer) newValue.get() - 2, false); } }); + this.thingState = new ThingStateChannels(this); } /* @@ -90,7 +94,6 @@ public ConfigChannel chargeSoc() { private StaticValueChannel maxNominalPower = new StaticValueChannel<>("maxNominalPower", this, 40000L) .unit("VA"); private StaticValueChannel capacity = new StaticValueChannel<>("capacity", this, 40000L).unit("Wh"); - public StatusBitChannels warning; @Override public ModbusReadLongChannel soc() { @@ -152,11 +155,6 @@ public ModbusReadLongChannel allowedApparent() { return allowedApparent; } - @Override - public StatusBitChannels warning() { - return warning; - } - @Override public ReadChannel maxNominalPower() { return maxNominalPower; @@ -210,13 +208,236 @@ public ReadChannel maxNominalPower() { public StatusBitChannel abnormity3; public StatusBitChannel abnormity4; public StatusBitChannel abnormity5; + public ModbusReadLongChannel batteryCell1Voltage; + public ModbusReadLongChannel batteryCell2Voltage; + public ModbusReadLongChannel batteryCell3Voltage; + public ModbusReadLongChannel batteryCell4Voltage; + public ModbusReadLongChannel batteryCell5Voltage; + public ModbusReadLongChannel batteryCell6Voltage; + public ModbusReadLongChannel batteryCell7Voltage; + public ModbusReadLongChannel batteryCell8Voltage; + public ModbusReadLongChannel batteryCell9Voltage; + public ModbusReadLongChannel batteryCell10Voltage; + public ModbusReadLongChannel batteryCell11Voltage; + public ModbusReadLongChannel batteryCell12Voltage; + public ModbusReadLongChannel batteryCell13Voltage; + public ModbusReadLongChannel batteryCell14Voltage; + public ModbusReadLongChannel batteryCell15Voltage; + public ModbusReadLongChannel batteryCell16Voltage; + public ModbusReadLongChannel batteryCell17Voltage; + public ModbusReadLongChannel batteryCell18Voltage; + public ModbusReadLongChannel batteryCell19Voltage; + public ModbusReadLongChannel batteryCell20Voltage; + public ModbusReadLongChannel batteryCell21Voltage; + public ModbusReadLongChannel batteryCell22Voltage; + public ModbusReadLongChannel batteryCell23Voltage; + public ModbusReadLongChannel batteryCell24Voltage; + public ModbusReadLongChannel batteryCell25Voltage; + public ModbusReadLongChannel batteryCell26Voltage; + public ModbusReadLongChannel batteryCell27Voltage; + public ModbusReadLongChannel batteryCell28Voltage; + public ModbusReadLongChannel batteryCell29Voltage; + public ModbusReadLongChannel batteryCell30Voltage; + public ModbusReadLongChannel batteryCell31Voltage; + public ModbusReadLongChannel batteryCell32Voltage; + public ModbusReadLongChannel batteryCell33Voltage; + public ModbusReadLongChannel batteryCell34Voltage; + public ModbusReadLongChannel batteryCell35Voltage; + public ModbusReadLongChannel batteryCell36Voltage; + public ModbusReadLongChannel batteryCell37Voltage; + public ModbusReadLongChannel batteryCell38Voltage; + public ModbusReadLongChannel batteryCell39Voltage; + public ModbusReadLongChannel batteryCell40Voltage; + public ModbusReadLongChannel batteryCell41Voltage; + public ModbusReadLongChannel batteryCell42Voltage; + public ModbusReadLongChannel batteryCell43Voltage; + public ModbusReadLongChannel batteryCell44Voltage; + public ModbusReadLongChannel batteryCell45Voltage; + public ModbusReadLongChannel batteryCell46Voltage; + public ModbusReadLongChannel batteryCell47Voltage; + public ModbusReadLongChannel batteryCell48Voltage; + public ModbusReadLongChannel batteryCell49Voltage; + public ModbusReadLongChannel batteryCell50Voltage; + public ModbusReadLongChannel batteryCell51Voltage; + public ModbusReadLongChannel batteryCell52Voltage; + public ModbusReadLongChannel batteryCell53Voltage; + public ModbusReadLongChannel batteryCell54Voltage; + public ModbusReadLongChannel batteryCell55Voltage; + public ModbusReadLongChannel batteryCell56Voltage; + public ModbusReadLongChannel batteryCell57Voltage; + public ModbusReadLongChannel batteryCell58Voltage; + public ModbusReadLongChannel batteryCell59Voltage; + public ModbusReadLongChannel batteryCell60Voltage; + public ModbusReadLongChannel batteryCell61Voltage; + public ModbusReadLongChannel batteryCell62Voltage; + public ModbusReadLongChannel batteryCell63Voltage; + public ModbusReadLongChannel batteryCell64Voltage; + public ModbusReadLongChannel batteryCell65Voltage; + public ModbusReadLongChannel batteryCell66Voltage; + public ModbusReadLongChannel batteryCell67Voltage; + public ModbusReadLongChannel batteryCell68Voltage; + public ModbusReadLongChannel batteryCell69Voltage; + public ModbusReadLongChannel batteryCell70Voltage; + public ModbusReadLongChannel batteryCell71Voltage; + public ModbusReadLongChannel batteryCell72Voltage; + public ModbusReadLongChannel batteryCell73Voltage; + public ModbusReadLongChannel batteryCell74Voltage; + public ModbusReadLongChannel batteryCell75Voltage; + public ModbusReadLongChannel batteryCell76Voltage; + public ModbusReadLongChannel batteryCell77Voltage; + public ModbusReadLongChannel batteryCell78Voltage; + public ModbusReadLongChannel batteryCell79Voltage; + public ModbusReadLongChannel batteryCell80Voltage; + public ModbusReadLongChannel batteryCell81Voltage; + public ModbusReadLongChannel batteryCell82Voltage; + public ModbusReadLongChannel batteryCell83Voltage; + public ModbusReadLongChannel batteryCell84Voltage; + public ModbusReadLongChannel batteryCell85Voltage; + public ModbusReadLongChannel batteryCell86Voltage; + public ModbusReadLongChannel batteryCell87Voltage; + public ModbusReadLongChannel batteryCell88Voltage; + public ModbusReadLongChannel batteryCell89Voltage; + public ModbusReadLongChannel batteryCell90Voltage; + public ModbusReadLongChannel batteryCell91Voltage; + public ModbusReadLongChannel batteryCell92Voltage; + public ModbusReadLongChannel batteryCell93Voltage; + public ModbusReadLongChannel batteryCell94Voltage; + public ModbusReadLongChannel batteryCell95Voltage; + public ModbusReadLongChannel batteryCell96Voltage; + public ModbusReadLongChannel batteryCell97Voltage; + public ModbusReadLongChannel batteryCell98Voltage; + public ModbusReadLongChannel batteryCell99Voltage; + public ModbusReadLongChannel batteryCell100Voltage; + public ModbusReadLongChannel batteryCell101Voltage; + public ModbusReadLongChannel batteryCell102Voltage; + public ModbusReadLongChannel batteryCell103Voltage; + public ModbusReadLongChannel batteryCell104Voltage; + public ModbusReadLongChannel batteryCell105Voltage; + public ModbusReadLongChannel batteryCell106Voltage; + public ModbusReadLongChannel batteryCell107Voltage; + public ModbusReadLongChannel batteryCell108Voltage; + public ModbusReadLongChannel batteryCell109Voltage; + public ModbusReadLongChannel batteryCell110Voltage; + public ModbusReadLongChannel batteryCell111Voltage; + public ModbusReadLongChannel batteryCell112Voltage; + public ModbusReadLongChannel batteryCell113Voltage; + public ModbusReadLongChannel batteryCell114Voltage; + public ModbusReadLongChannel batteryCell115Voltage; + public ModbusReadLongChannel batteryCell116Voltage; + public ModbusReadLongChannel batteryCell117Voltage; + public ModbusReadLongChannel batteryCell118Voltage; + public ModbusReadLongChannel batteryCell119Voltage; + public ModbusReadLongChannel batteryCell120Voltage; + public ModbusReadLongChannel batteryCell121Voltage; + public ModbusReadLongChannel batteryCell122Voltage; + public ModbusReadLongChannel batteryCell123Voltage; + public ModbusReadLongChannel batteryCell124Voltage; + public ModbusReadLongChannel batteryCell125Voltage; + public ModbusReadLongChannel batteryCell126Voltage; + public ModbusReadLongChannel batteryCell127Voltage; + public ModbusReadLongChannel batteryCell128Voltage; + public ModbusReadLongChannel batteryCell129Voltage; + public ModbusReadLongChannel batteryCell130Voltage; + public ModbusReadLongChannel batteryCell131Voltage; + public ModbusReadLongChannel batteryCell132Voltage; + public ModbusReadLongChannel batteryCell133Voltage; + public ModbusReadLongChannel batteryCell134Voltage; + public ModbusReadLongChannel batteryCell135Voltage; + public ModbusReadLongChannel batteryCell136Voltage; + public ModbusReadLongChannel batteryCell137Voltage; + public ModbusReadLongChannel batteryCell138Voltage; + public ModbusReadLongChannel batteryCell139Voltage; + public ModbusReadLongChannel batteryCell140Voltage; + public ModbusReadLongChannel batteryCell141Voltage; + public ModbusReadLongChannel batteryCell142Voltage; + public ModbusReadLongChannel batteryCell143Voltage; + public ModbusReadLongChannel batteryCell144Voltage; + public ModbusReadLongChannel batteryCell145Voltage; + public ModbusReadLongChannel batteryCell146Voltage; + public ModbusReadLongChannel batteryCell147Voltage; + public ModbusReadLongChannel batteryCell148Voltage; + public ModbusReadLongChannel batteryCell149Voltage; + public ModbusReadLongChannel batteryCell150Voltage; + public ModbusReadLongChannel batteryCell151Voltage; + public ModbusReadLongChannel batteryCell152Voltage; + public ModbusReadLongChannel batteryCell153Voltage; + public ModbusReadLongChannel batteryCell154Voltage; + public ModbusReadLongChannel batteryCell155Voltage; + public ModbusReadLongChannel batteryCell156Voltage; + public ModbusReadLongChannel batteryCell157Voltage; + public ModbusReadLongChannel batteryCell158Voltage; + public ModbusReadLongChannel batteryCell159Voltage; + public ModbusReadLongChannel batteryCell160Voltage; + public ModbusReadLongChannel batteryCell161Voltage; + public ModbusReadLongChannel batteryCell162Voltage; + public ModbusReadLongChannel batteryCell163Voltage; + public ModbusReadLongChannel batteryCell164Voltage; + public ModbusReadLongChannel batteryCell165Voltage; + public ModbusReadLongChannel batteryCell166Voltage; + public ModbusReadLongChannel batteryCell167Voltage; + public ModbusReadLongChannel batteryCell168Voltage; + public ModbusReadLongChannel batteryCell169Voltage; + public ModbusReadLongChannel batteryCell170Voltage; + public ModbusReadLongChannel batteryCell171Voltage; + public ModbusReadLongChannel batteryCell172Voltage; + public ModbusReadLongChannel batteryCell173Voltage; + public ModbusReadLongChannel batteryCell174Voltage; + public ModbusReadLongChannel batteryCell175Voltage; + public ModbusReadLongChannel batteryCell176Voltage; + public ModbusReadLongChannel batteryCell177Voltage; + public ModbusReadLongChannel batteryCell178Voltage; + public ModbusReadLongChannel batteryCell179Voltage; + public ModbusReadLongChannel batteryCell180Voltage; + public ModbusReadLongChannel batteryCell181Voltage; + public ModbusReadLongChannel batteryCell182Voltage; + public ModbusReadLongChannel batteryCell183Voltage; + public ModbusReadLongChannel batteryCell184Voltage; + public ModbusReadLongChannel batteryCell185Voltage; + public ModbusReadLongChannel batteryCell186Voltage; + public ModbusReadLongChannel batteryCell187Voltage; + public ModbusReadLongChannel batteryCell188Voltage; + public ModbusReadLongChannel batteryCell189Voltage; + public ModbusReadLongChannel batteryCell190Voltage; + public ModbusReadLongChannel batteryCell191Voltage; + public ModbusReadLongChannel batteryCell192Voltage; + public ModbusReadLongChannel batteryCell193Voltage; + public ModbusReadLongChannel batteryCell194Voltage; + public ModbusReadLongChannel batteryCell195Voltage; + public ModbusReadLongChannel batteryCell196Voltage; + public ModbusReadLongChannel batteryCell197Voltage; + public ModbusReadLongChannel batteryCell198Voltage; + public ModbusReadLongChannel batteryCell199Voltage; + public ModbusReadLongChannel batteryCell200Voltage; + public ModbusReadLongChannel batteryCell201Voltage; + public ModbusReadLongChannel batteryCell202Voltage; + public ModbusReadLongChannel batteryCell203Voltage; + public ModbusReadLongChannel batteryCell204Voltage; + public ModbusReadLongChannel batteryCell205Voltage; + public ModbusReadLongChannel batteryCell206Voltage; + public ModbusReadLongChannel batteryCell207Voltage; + public ModbusReadLongChannel batteryCell208Voltage; + public ModbusReadLongChannel batteryCell209Voltage; + public ModbusReadLongChannel batteryCell210Voltage; + public ModbusReadLongChannel batteryCell211Voltage; + public ModbusReadLongChannel batteryCell212Voltage; + public ModbusReadLongChannel batteryCell213Voltage; + public ModbusReadLongChannel batteryCell214Voltage; + public ModbusReadLongChannel batteryCell215Voltage; + public ModbusReadLongChannel batteryCell216Voltage; + public ModbusReadLongChannel batteryCell217Voltage; + public ModbusReadLongChannel batteryCell218Voltage; + public ModbusReadLongChannel batteryCell219Voltage; + public ModbusReadLongChannel batteryCell220Voltage; + public ModbusReadLongChannel batteryCell221Voltage; + public ModbusReadLongChannel batteryCell222Voltage; + public ModbusReadLongChannel batteryCell223Voltage; + public ModbusReadLongChannel batteryCell224Voltage; /* * Methods */ @Override protected ModbusProtocol defineModbusProtocol() throws ConfigException { - warning = new StatusBitChannels("Warning", this); return new ModbusProtocol( // new ModbusRegisterRange(0x0101, // new UnsignedWordElement(0x0101, // @@ -261,30 +482,35 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { .label(1, "CESS")), // new DummyElement(0x010B, 0x010F), // new UnsignedWordElement(0x0110, // - suggestiveInformation1 = warning - .channel(new StatusBitChannel("SuggestiveInformation1", this) // - .label(4, "EmergencyStop") // - .label(64, "KeyManualStop"))), // + new ModbusBitWrappingChannel("SuggestiveInformation1", this, this.thingState) // + .warningBit(2, WarningEss.EmergencyStop) // EmergencyStop + .warningBit(6, WarningEss.KeyManualStop)), // KeyManualStop new UnsignedWordElement(0x0111, // - suggestiveInformation2 = warning - .channel(new StatusBitChannel("SuggestiveInformation2", this) // - .label(4, "EmergencyStop") // - .label(64, "KeyManualStop"))), // + new ModbusBitWrappingChannel("SuggestiveInformation2", this, this.thingState) // + .warningBit(3, WarningEss.TransformerPhaseBTemperatureSensorInvalidation) // Transformer + // phase + // B + // temperature + // sensor + // invalidation + .warningBit(12, WarningEss.SDMemoryCardInvalidation)), // SD memory card + // invalidation new DummyElement(0x0112, 0x0124), // new UnsignedWordElement(0x0125, // - suggestiveInformation3 = warning - .channel(new StatusBitChannel("SuggestiveInformation3", this) // - .label(1, "Inverter communication abnormity") // - .label(2, "Battery stack communication abnormity") // - .label(4, "Multifunctional ammeter communication abnormity") // - .label(16, "Remote communication abnormity")// - .label(256, "PV DC1 communication abnormity")// - .label(512, "PV DC2 communication abnormity")// - )), // + new ModbusBitWrappingChannel("SuggestiveInformation3", this, this.thingState)// + .warningBit(0, WarningEss.InverterCommunicationAbnormity)// + .warningBit(1, WarningEss.BatteryStackCommunicationAbnormity)// + .warningBit(2, WarningEss.MultifunctionalAmmeterCommunicationAbnormity)// + .warningBit(4, WarningEss.RemoteCommunicationAbnormity)// + .warningBit(8, WarningEss.PVDC1CommunicationAbnormity)// + .warningBit(9, WarningEss.PVDC2CommunicationAbnormity)// + ), // + new UnsignedWordElement(0x0126, // - suggestiveInformation4 = warning - .channel(new StatusBitChannel("SuggestiveInformation4", this) // - .label(8, "Transformer severe overtemperature"))), // + new ModbusBitWrappingChannel("SuggestiveInformation4", this, this.thingState)// + .warningBit(3, WarningEss.TransformerSevereOvertemperature)// + ), // + new DummyElement(0x0127, 0x014F), // new UnsignedWordElement(0x0150, // switchState = new StatusBitChannel("BatteryStringSwitchState", this) // @@ -295,139 +521,151 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { .label(16, "Middle relay"))// ), // new ModbusRegisterRange(0x0180, // - new UnsignedWordElement(0x0180, - abnormity1 = warning.channel(new StatusBitChannel("Abnormity1", this)// - .label(1, "DC precharge contactor close unsuccessfully") // - .label(2, "AC precharge contactor close unsuccessfully") // - .label(4, "AC main contactor close unsuccessfully") // - .label(8, "DC electrical breaker 1 close unsuccessfully") // - .label(16, "DC main contactor close unsuccessfully") // - .label(32, "AC breaker trip") // - .label(64, "AC main contactor open when running") // - .label(128, "DC main contactor open when running") // - .label(256, "AC main contactor open unsuccessfully") // - .label(512, "DC electrical breaker 1 open unsuccessfully") // - .label(1024, "DC main contactor open unsuccessfully") // - .label(2048, "Hardware PDP fault") // - .label(4096, "Master stop suddenly"))), - new DummyElement(0x0181), - new UnsignedWordElement(0x0182, - abnormity2 = warning.channel(new StatusBitChannel("Abnormity2", this) // - .label(1, "DC short circuit protection") // - .label(2, "DC overvoltage protection") // - .label(4, "DC undervoltage protection") // - .label(8, "DC inverse/no connection protection") // - .label(16, "DC disconnection protection") // - .label(32, "Commuting voltage abnormity protection") // - .label(64, "DC overcurrent protection") // - .label(128, "Phase 1 peak current over limit protection") // - .label(256, "Phase 2 peak current over limit protection") // - .label(512, "Phase 3 peak current over limit protection") // - .label(1024, "Phase 1 grid voltage sampling invalidation") // - .label(2048, "Phase 2 virtual current over limit protection") // - .label(4096, "Phase 3 virtual current over limit protection") // - .label(8192, "Phase 1 grid voltage sampling invalidation2") // TODO same as - // above - .label(16384, "Phase 2 grid voltage sampling invalidation") // - .label(32768, "Phase 3 grid voltage sampling invalidation"))), - new UnsignedWordElement(0x0183, - abnormity3 = warning.channel(new StatusBitChannel("Abnormity3", this) // - .label(1, "Phase 1 invert voltage sampling invalidation") // - .label(2, "Phase 2 invert voltage sampling invalidation") // - .label(4, "Phase 3 invert voltage sampling invalidation") // - .label(8, "AC current sampling invalidation") // - .label(16, "DC current sampling invalidation") // - .label(32, "Phase 1 overtemperature protection") // - .label(64, "Phase 2 overtemperature protection") // - .label(128, "Phase 3 overtemperature protection") // - .label(256, "Phase 1 temperature sampling invalidation") // - .label(512, "Phase 2 temperature sampling invalidation") // - .label(1024, "Phase 3 temperature sampling invalidation") // - .label(2048, "Phase 1 precharge unmet protection") // - .label(4096, "Phase 2 precharge unmet protection") // - .label(8192, "Phase 3 precharge unmet protection") // - .label(16384, "Unadaptable phase sequence error protection")// - .label(132768, "DSP protection"))), - new UnsignedWordElement(0x0184, - abnormity4 = warning.channel(new StatusBitChannel("Abnormity4", this) // - .label(1, "Phase 1 grid voltage severe overvoltage protection") // - .label(2, "Phase 1 grid voltage general overvoltage protection") // - .label(4, "Phase 2 grid voltage severe overvoltage protection") // - .label(8, "Phase 2 grid voltage general overvoltage protection") // - .label(16, "Phase 3 grid voltage severe overvoltage protection") // - .label(32, "Phase 3 grid voltage general overvoltage protection") // - .label(64, "Phase 1 grid voltage severe undervoltage protection") // - .label(128, "Phase 1 grid voltage general undervoltage protection") // - .label(256, "Phase 2 grid voltage severe undervoltage protection") // - .label(512, "Phase 2 grid voltage general undervoltage protection") // - .label(1024, "Phase 2 Inverter voltage general overvoltage protection") // - .label(2048, "Phase 3 Inverter voltage severe overvoltage protection") // - .label(4096, "Phase 3 Inverter voltage general overvoltage protection") // - .label(8192, "Inverter peak voltage high protection cause by AC disconnect"))), - new UnsignedWordElement(0x0185, - abnormity5 = warning.channel(new StatusBitChannel("Abnormity5", this) // - .label(1, "Phase 1 grid loss") // - .label(2, "Phase 2 grid loss") // - .label(4, "Phase 3 grid loss") // - .label(8, "Islanding protection") // - .label(16, "Phase 1 under voltage ride through") // - .label(32, "Phase 2 under voltage ride through") // - .label(64, "Phase 3 under voltage ride through ") // - .label(128, "Phase 1 Inverter voltage severe overvoltage protection") // - .label(256, "Phase 1 Inverter voltage general overvoltage protection") // - .label(512, "Phase 2 Inverter voltage severe overvoltage protection") // - .label(1024, "Phase 2 Inverter voltage general overvoltage protection") // - .label(2048, "Phase 3 Inverter voltage severe overvoltage protection") // - .label(4096, "Phase 3 Inverter voltage general overvoltage protection") // - .label(8192, "Inverter peak voltage high protection cause by AC disconnect"))), - new UnsignedWordElement(0x0186, - suggestiveInformation5 = warning - .channel(new StatusBitChannel("SuggestiveInformation5", this) // - .label(1, "DC precharge contactor inspection abnormity") // - .label(2, "DC breaker 1 inspection abnormity ") // - .label(4, "DC breaker 2 inspection abnormity ") // - .label(8, "AC precharge contactor inspection abnormity ") // - .label(16, "AC main contactor inspection abnormity ") // - .label(32, "AC breaker inspection abnormity ") // - .label(64, "DC breaker 1 close unsuccessfully") // - .label(128, "DC breaker 2 close unsuccessfully") // - .label(256, "Control signal close abnormally inspected by system") // - .label(512, "Control signal open abnormally inspected by system") // - .label(1024, "Neutral wire contactor close unsuccessfully") // - .label(2048, "Neutral wire contactor open unsuccessfully") // - .label(4096, "Work door open") // - .label(8192, "Emergency stop") // - .label(16384, "AC breaker close unsuccessfully")// - .label(132768, "Control switch stop"))), - new UnsignedWordElement(0x0187, - suggestiveInformation6 = warning - .channel(new StatusBitChannel("SuggestiveInformation6", this) // - .label(1, "General overload") // - .label(2, "Severe overload") // - .label(4, "Battery current over limit") // - .label(8, "Power decrease caused by overtemperature") // - .label(16, "Inverter general overtemperature") // - .label(32, "AC three-phase current unbalance") // - .label(64, "Rstore factory setting unsuccessfully") // - .label(128, "Pole-board invalidation") // - .label(256, "Self-inspection failed") // - .label(512, "Receive BMS fault and stop") // - .label(1024, "Refrigeration equipment invalidation") // - .label(2048, "Large temperature difference among IGBT three phases") // - .label(4096, "EEPROM parameters over range") // - .label(8192, "EEPROM parameters backup failed") // - .label(16384, "DC breaker close unsuccessfully"))), - new UnsignedWordElement(0x0188, - suggestiveInformation7 = warning - .channel(new StatusBitChannel("SuggestiveInformation7", this) // - .label(1, "Communication between inverter and BSMU disconnected") // - .label(2, "Communication between inverter and Master disconnected") // - .label(4, "Communication between inverter and UC disconnected") // - .label(8, "BMS start overtime controlled by PCS") // - .label(16, "BMS stop overtime controlled by PCS") // - .label(32, "Sync signal invalidation") // - .label(64, "Sync signal continuous caputure fault") // - .label(128, "Sync signal several times caputure fault")))), + new UnsignedWordElement(0x0180, // + new ModbusBitWrappingChannel("Abnormity1", this, this.thingState)// + .faultBit(0, FaultEss.DCPrechargeContactorCloseUnsuccessfully)// + .faultBit(1, FaultEss.ACPrechargeContactorCloseUnsuccessfully)// + .faultBit(2, FaultEss.ACMainContactorCloseUnsuccessfully)// + .faultBit(3, FaultEss.DCElectricalBreaker1CloseUnsuccessfully)// + .faultBit(4, FaultEss.DCMainContactorCloseUnsuccessfully)// + .faultBit(5, FaultEss.ACBreakerTrip)// + .faultBit(6, FaultEss.ACMainContactorOpenWhenRunning)// + .faultBit(7, FaultEss.DCMainContactorOpenWhenRunning)// + .faultBit(8, FaultEss.ACMainContactorOpenUnsuccessfully)// + .faultBit(9, FaultEss.DCElectricalBreaker1OpenUnsuccessfully)// + .faultBit(10, FaultEss.DCMainContactorOpenUnsuccessfully)// + .faultBit(11, FaultEss.HardwarePDPFault)// + .faultBit(12, FaultEss.MasterStopSuddenly)// + ), + + new DummyElement(0x0181), new UnsignedWordElement(0x0182, // + new ModbusBitWrappingChannel("Abnormity2", this, this.thingState)// + .faultBit(0, FaultEss.DCShortCircuitProtection)// + .faultBit(1, FaultEss.DCOvervoltageProtection)// + .faultBit(2, FaultEss.DCUndervoltageProtection)// + .faultBit(3, FaultEss.DCInverseNoConnectionProtection)// + .faultBit(4, FaultEss.DCDisconnectionProtection)// + .faultBit(5, FaultEss.CommutingVoltageAbnormityProtection)// + .faultBit(6, FaultEss.DCOvercurrentProtection)// + .faultBit(7, FaultEss.Phase1PeakCurrentOverLimitProtection)// + .faultBit(8, FaultEss.Phase2PeakCurrentOverLimitProtection)// + .faultBit(9, FaultEss.Phase3PeakCurrentOverLimitProtection)// + .faultBit(10,FaultEss.Phase1GridVoltageSamplingInvalidation)// + .faultBit(11, FaultEss.Phase2VirtualCurrentOverLimitProtection)// + .faultBit(12, FaultEss.Phase3VirtualCurrentOverLimitProtection)// + .faultBit(13, FaultEss.Phase1GridVoltageSamplingInvalidation2)// TODO same as + // above + .faultBit(14, FaultEss.Phase2ridVoltageSamplingInvalidation)// + .faultBit(15, FaultEss.Phase3GridVoltageSamplingInvalidation)// + ), // + + new UnsignedWordElement(0x0183, // + new ModbusBitWrappingChannel("Abnormity3", this, this.thingState)// + .faultBit(0, FaultEss.Phase1InvertVoltageSamplingInvalidation)// + .faultBit(1, FaultEss.Phase2InvertVoltageSamplingInvalidation)// + .faultBit(2, FaultEss.Phase3InvertVoltageSamplingInvalidation)// + .faultBit(3, FaultEss.ACCurrentSamplingInvalidation)// + .faultBit(4, FaultEss.DCCurrentSamplingInvalidation)// + .faultBit(5, FaultEss.Phase1OvertemperatureProtection)// + .faultBit(6, FaultEss.Phase2OvertemperatureProtection)// + .faultBit(7, FaultEss.Phase3OvertemperatureProtection)// + .faultBit(8, FaultEss.Phase1TemperatureSamplingInvalidation)// + .faultBit(9, FaultEss.Phase2TemperatureSamplingInvalidation)// + .faultBit(10, FaultEss.Phase3TemperatureSamplingInvalidation)// + .faultBit(11, FaultEss.Phase1PrechargeUnmetProtection)// + .faultBit(12, FaultEss.Phase2PrechargeUnmetProtection)// + .faultBit(13, FaultEss.Phase3PrechargeUnmetProtection)// + .faultBit(14, FaultEss.UnadaptablePhaseSequenceErrorProtection)// + .faultBit(15, FaultEss.DSPProtection)// + ), // + + new UnsignedWordElement(0x0184, // + new ModbusBitWrappingChannel("Abnormity4", this, this.thingState)// + .faultBit(0, FaultEss.Phase1GridVoltageSevereOvervoltageProtection)// + .faultBit(1, FaultEss.Phase1GridVoltageGeneralOvervoltageProtection)// + .faultBit(2, FaultEss.Phase2GridVoltageSevereOvervoltageProtection)// + .faultBit(3, FaultEss.Phase2GridVoltageGeneralOvervoltageProtection)// + .faultBit(4, FaultEss.Phase3GridVoltageSevereOvervoltageProtection)// + .faultBit(5, FaultEss.Phase3GridVoltageGeneralOvervoltageProtection)// + .faultBit(6, FaultEss.Phase1GridVoltageSevereUndervoltageProtection)// + .faultBit(7, FaultEss.Phase1GridVoltageGeneralUndervoltageProtection)// + .faultBit(8, FaultEss.Phase2GridVoltageSevereUndervoltageProtection)// + .faultBit(9, FaultEss.Phase2GridVoltageGeneralUndervoltageProtection)// + .faultBit(10, FaultEss.Phase3GridVoltageSevereUndervoltageProtection)// + .faultBit(11, FaultEss.Phase3GridVoltageGeneralUndervoltageProtection)// + .faultBit(12, FaultEss.SevereOverfrequncyProtection)// + .faultBit(13, FaultEss.GeneralOverfrequncyProtection)// + .faultBit(14, FaultEss.SevereUnderfrequncyProtection)// + .faultBit(15, FaultEss.GeneralsUnderfrequncyProtection)// + ), // + + new UnsignedWordElement(0x0185, // + new ModbusBitWrappingChannel("Abnormity5", this, this.thingState)// + .faultBit(0, FaultEss.Phase1Gridloss)// + .faultBit(1, FaultEss.Phase2Gridloss)// + .faultBit(2, FaultEss.Phase3Gridloss)// + .faultBit(3, FaultEss.IslandingProtection)// + .faultBit(4, FaultEss.Phase1UnderVoltageRideThrough)// + .faultBit(5, FaultEss.Phase2UnderVoltageRideThrough)// + .faultBit(6, FaultEss.Phase3UnderVoltageRideThrough)// + .faultBit(7, FaultEss.Phase1InverterVoltageSevereOvervoltageProtection)// + .faultBit(8, FaultEss.Phase1InverterVoltageGeneralOvervoltageProtection)// + .faultBit(9, FaultEss.Phase2InverterVoltageSevereOvervoltageProtection)// + .faultBit(10, FaultEss.Phase2InverterVoltageGeneralOvervoltageProtection)// + .faultBit(11, FaultEss.Phase3InverterVoltageSevereOvervoltageProtection)// + .faultBit(12, FaultEss.Phase3InverterVoltageGeneralOvervoltageProtection)// + .faultBit(13, FaultEss.InverterPeakVoltageHighProtectionCauseByACDisconnect)// + ), // + + new UnsignedWordElement(0x0186, // + new ModbusBitWrappingChannel("SuggestiveInformation5", this, this.thingState)// + .warningBit(0, WarningEss.DCPrechargeContactorInspectionAbnormity)// + .warningBit(1, WarningEss.DCBreaker1InspectionAbnormity)// + .warningBit(2, WarningEss.DCBreaker2InspectionAbnormity)// + .warningBit(3, WarningEss.ACPrechargeContactorInspectionAbnormity)// + .warningBit(4, WarningEss.ACMainontactorInspectionAbnormity)// + .warningBit(5, WarningEss.ACBreakerInspectionAbnormity)// + .warningBit(6, WarningEss.DCBreaker1CloseUnsuccessfully)// + .warningBit(7, WarningEss.DCBreaker2CloseUnsuccessfully)// + .warningBit(8, WarningEss.ControlSignalCloseAbnormallyInspectedBySystem)// + .warningBit(9, WarningEss.ControlSignalOpenAbnormallyInspectedBySystem)// + .warningBit(10, WarningEss.NeutralWireContactorCloseUnsuccessfully)// + .warningBit(11, WarningEss.NeutralWireContactorOpenUnsuccessfully)// + .warningBit(12, WarningEss.WorkDoorOpen)// + .warningBit(13, WarningEss.Emergency1Stop)// + .warningBit(14, WarningEss.ACBreakerCloseUnsuccessfully)// + .warningBit(15, WarningEss.ControlSwitchStop)// + ), // + + new UnsignedWordElement(0x0187, // + new ModbusBitWrappingChannel("SuggestiveInformation6", this, this.thingState)// + .warningBit(0, WarningEss.GeneralOverload)// + .warningBit(1, WarningEss.SevereOverload)// + .warningBit(2, WarningEss.BatteryCurrentOverLimit)// + .warningBit(3, WarningEss.PowerDecreaseCausedByOvertemperature)// + .warningBit(4, WarningEss.InverterGeneralOvertemperature)// + .warningBit(5, WarningEss.ACThreePhaseCurrentUnbalance)// + .warningBit(6, WarningEss.RestoreFactorySettingUnsuccessfully)// + .warningBit(7, WarningEss.PoleBoardInvalidation)// + .warningBit(8, WarningEss.SelfInspectionFailed)// + .warningBit(9, WarningEss.ReceiveBMSFaultAndStop)// + .warningBit(10, WarningEss.RefrigerationEquipmentinvalidation)// + .warningBit(11, WarningEss.LargeTemperatureDifferenceAmongIGBTThreePhases)// + .warningBit(12, WarningEss.EEPROMParametersOverRange)// + .warningBit(13, WarningEss.EEPROMParametersBackupFailed)// + .warningBit(14, WarningEss.DCBreakerCloseunsuccessfully)// + ), // + new UnsignedWordElement(0x0188, // + new ModbusBitWrappingChannel("SuggestiveInformation7", this, this.thingState)// + .warningBit(0, WarningEss.CommunicationBetweenInverterAndBSMUDisconnected)// + .warningBit(1, WarningEss.CommunicationBetweenInverterAndMasterDisconnected)// + .warningBit(2, WarningEss.CommunicationBetweenInverterAndUCDisconnected)// + .warningBit(3, WarningEss.BMSStartOvertimeControlledByPCS)// + .warningBit(4, WarningEss.BMSStopOvertimeControlledByPCS)// + .warningBit(5, WarningEss.SyncSignalInvalidation)// + .warningBit(6, WarningEss.SyncSignalContinuousCaputureFault)// + .warningBit(7, WarningEss.SyncSignalSeveralTimesCaputureFault))), + new ModbusRegisterRange(0x0200, // new SignedWordElement(0x0200, // batteryVoltage = new ModbusReadLongChannel("BatteryVoltage", this).unit("mV") @@ -528,8 +766,683 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { new UnsignedWordElement(0x1403, soh = new ModbusReadLongChannel("Soh", this).unit("%").interval(0, 100)), new UnsignedWordElement(0x1404, - batteryCellAverageTemperature = new ModbusReadLongChannel("BatteryCellAverageTemperature", this).unit("°C")) - )); + batteryCellAverageTemperature = new ModbusReadLongChannel( + "BatteryCellAverageTemperature", this).unit("°C"))), + new ModbusRegisterRange(0x1500, // + new UnsignedWordElement(0x1500, + batteryCell1Voltage = new ModbusReadLongChannel("Cell1Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1501, + batteryCell2Voltage = new ModbusReadLongChannel("Cell2Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1502, + batteryCell3Voltage = new ModbusReadLongChannel("Cell3Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1503, + batteryCell4Voltage = new ModbusReadLongChannel("Cell4Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1504, + batteryCell5Voltage = new ModbusReadLongChannel("Cell5Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1505, + batteryCell6Voltage = new ModbusReadLongChannel("Cell6Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1506, + batteryCell7Voltage = new ModbusReadLongChannel("Cell7Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1507, + batteryCell8Voltage = new ModbusReadLongChannel("Cell8Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1508, + batteryCell9Voltage = new ModbusReadLongChannel("Cell9Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1509, + batteryCell10Voltage = new ModbusReadLongChannel("Cell10Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x150A, + batteryCell11Voltage = new ModbusReadLongChannel("Cell11Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x150B, + batteryCell12Voltage = new ModbusReadLongChannel("Cell12Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x150C, + batteryCell13Voltage = new ModbusReadLongChannel("Cell13Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x150D, + batteryCell14Voltage = new ModbusReadLongChannel("Cell14Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x150E, + batteryCell15Voltage = new ModbusReadLongChannel("Cell15Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x150F, + batteryCell16Voltage = new ModbusReadLongChannel("Cell16Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1510, + batteryCell17Voltage = new ModbusReadLongChannel("Cell17Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1511, + batteryCell18Voltage = new ModbusReadLongChannel("Cell18Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1512, + batteryCell19Voltage = new ModbusReadLongChannel("Cell19Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1513, + batteryCell20Voltage = new ModbusReadLongChannel("Cell20Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1514, + batteryCell21Voltage = new ModbusReadLongChannel("Cell21Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1515, + batteryCell22Voltage = new ModbusReadLongChannel("Cell22Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1516, + batteryCell23Voltage = new ModbusReadLongChannel("Cell23Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1517, + batteryCell24Voltage = new ModbusReadLongChannel("Cell24Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1518, + batteryCell25Voltage = new ModbusReadLongChannel("Cell25Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1519, + batteryCell26Voltage = new ModbusReadLongChannel("Cell26Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x151A, + batteryCell27Voltage = new ModbusReadLongChannel("Cell27Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x151B, + batteryCell28Voltage = new ModbusReadLongChannel("Cell28Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x151C, + batteryCell29Voltage = new ModbusReadLongChannel("Cell29Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x151D, + batteryCell30Voltage = new ModbusReadLongChannel("Cell30Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x151E, + batteryCell31Voltage = new ModbusReadLongChannel("Cell31Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x151F, + batteryCell32Voltage = new ModbusReadLongChannel("Cell32Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1520, + batteryCell33Voltage = new ModbusReadLongChannel("Cell33Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1521, + batteryCell34Voltage = new ModbusReadLongChannel("Cell34Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1522, + batteryCell35Voltage = new ModbusReadLongChannel("Cell35Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1523, + batteryCell36Voltage = new ModbusReadLongChannel("Cell36Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1524, + batteryCell37Voltage = new ModbusReadLongChannel("Cell37Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1525, + batteryCell38Voltage = new ModbusReadLongChannel("Cell38Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1526, + batteryCell39Voltage = new ModbusReadLongChannel("Cell39Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1527, + batteryCell40Voltage = new ModbusReadLongChannel("Cell40Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1528, + batteryCell41Voltage = new ModbusReadLongChannel("Cell41Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1529, + batteryCell42Voltage = new ModbusReadLongChannel("Cell42Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x152A, + batteryCell43Voltage = new ModbusReadLongChannel("Cell43Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x152B, + batteryCell44Voltage = new ModbusReadLongChannel("Cell44Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x152C, + batteryCell45Voltage = new ModbusReadLongChannel("Cell45Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x152D, + batteryCell46Voltage = new ModbusReadLongChannel("Cell46Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x152E, + batteryCell47Voltage = new ModbusReadLongChannel("Cell47Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x152F, + batteryCell48Voltage = new ModbusReadLongChannel("Cell48Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1530, + batteryCell49Voltage = new ModbusReadLongChannel("Cell49Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1531, + batteryCell50Voltage = new ModbusReadLongChannel("Cell50Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1532, + batteryCell51Voltage = new ModbusReadLongChannel("Cell51Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1533, + batteryCell52Voltage = new ModbusReadLongChannel("Cell52Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1534, + batteryCell53Voltage = new ModbusReadLongChannel("Cell53Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1535, + batteryCell54Voltage = new ModbusReadLongChannel("Cell54Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1536, + batteryCell55Voltage = new ModbusReadLongChannel("Cell55Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1537, + batteryCell56Voltage = new ModbusReadLongChannel("Cell56Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1538, + batteryCell57Voltage = new ModbusReadLongChannel("Cell57Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1539, + batteryCell58Voltage = new ModbusReadLongChannel("Cell58Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x153A, + batteryCell59Voltage = new ModbusReadLongChannel("Cell59Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x153B, + batteryCell60Voltage = new ModbusReadLongChannel("Cell60Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x153C, + batteryCell61Voltage = new ModbusReadLongChannel("Cell61Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x153D, + batteryCell62Voltage = new ModbusReadLongChannel("Cell62Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x153E, + batteryCell63Voltage = new ModbusReadLongChannel("Cell63Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x153F, + batteryCell64Voltage = new ModbusReadLongChannel("Cell64Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1540, + batteryCell65Voltage = new ModbusReadLongChannel("Cell65Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1541, + batteryCell66Voltage = new ModbusReadLongChannel("Cell66Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1542, + batteryCell67Voltage = new ModbusReadLongChannel("Cell67Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1543, + batteryCell68Voltage = new ModbusReadLongChannel("Cell68Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1544, + batteryCell69Voltage = new ModbusReadLongChannel("Cell69Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1545, + batteryCell70Voltage = new ModbusReadLongChannel("Cell70Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1546, + batteryCell71Voltage = new ModbusReadLongChannel("Cell71Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1547, + batteryCell72Voltage = new ModbusReadLongChannel("Cell72Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1548, + batteryCell73Voltage = new ModbusReadLongChannel("Cell73Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1549, + batteryCell74Voltage = new ModbusReadLongChannel("Cell74Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x154A, + batteryCell75Voltage = new ModbusReadLongChannel("Cell75Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x154B, + batteryCell76Voltage = new ModbusReadLongChannel("Cell76Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x154C, + batteryCell77Voltage = new ModbusReadLongChannel("Cell77Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x154D, + batteryCell78Voltage = new ModbusReadLongChannel("Cell78Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x154E, + batteryCell79Voltage = new ModbusReadLongChannel("Cell79Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x154F, + batteryCell80Voltage = new ModbusReadLongChannel("Cell80Voltage", this).unit("mV") + )), + new ModbusRegisterRange(0x1550, // + new UnsignedWordElement(0x1550, + batteryCell81Voltage = new ModbusReadLongChannel("Cell81Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1551, + batteryCell82Voltage = new ModbusReadLongChannel("Cell82Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1552, + batteryCell83Voltage = new ModbusReadLongChannel("Cell83Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1553, + batteryCell84Voltage = new ModbusReadLongChannel("Cell84Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1554, + batteryCell85Voltage = new ModbusReadLongChannel("Cell85Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1555, + batteryCell86Voltage = new ModbusReadLongChannel("Cell86Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1556, + batteryCell87Voltage = new ModbusReadLongChannel("Cell87Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1557, + batteryCell88Voltage = new ModbusReadLongChannel("Cell88Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1558, + batteryCell89Voltage = new ModbusReadLongChannel("Cell89Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1559, + batteryCell90Voltage = new ModbusReadLongChannel("Cell90Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x155A, + batteryCell91Voltage = new ModbusReadLongChannel("Cell91Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x155B, + batteryCell92Voltage = new ModbusReadLongChannel("Cell92Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x155C, + batteryCell93Voltage = new ModbusReadLongChannel("Cell93Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x155D, + batteryCell94Voltage = new ModbusReadLongChannel("Cell94Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x155E, + batteryCell95Voltage = new ModbusReadLongChannel("Cell95Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x155F, + batteryCell96Voltage = new ModbusReadLongChannel("Cell96Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1560, + batteryCell97Voltage = new ModbusReadLongChannel("Cell97Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1561, + batteryCell98Voltage = new ModbusReadLongChannel("Cell98Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1562, + batteryCell99Voltage = new ModbusReadLongChannel("Cell99Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1563, + batteryCell100Voltage = new ModbusReadLongChannel("Cell100Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1564, + batteryCell101Voltage = new ModbusReadLongChannel("Cell101Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1565, + batteryCell102Voltage = new ModbusReadLongChannel("Cell102Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1566, + batteryCell103Voltage = new ModbusReadLongChannel("Cell103Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1567, + batteryCell104Voltage = new ModbusReadLongChannel("Cell104Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1568, + batteryCell105Voltage = new ModbusReadLongChannel("Cell105Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1569, + batteryCell106Voltage = new ModbusReadLongChannel("Cell106Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x156A, + batteryCell107Voltage = new ModbusReadLongChannel("Cell107Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x156B, + batteryCell108Voltage = new ModbusReadLongChannel("Cell108Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x156C, + batteryCell109Voltage = new ModbusReadLongChannel("Cell109Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x156D, + batteryCell110Voltage = new ModbusReadLongChannel("Cell110Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x156E, + batteryCell111Voltage = new ModbusReadLongChannel("Cell111Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x156F, + batteryCell112Voltage = new ModbusReadLongChannel("Cell112Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1570, + batteryCell113Voltage = new ModbusReadLongChannel("Cell113Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1571, + batteryCell114Voltage = new ModbusReadLongChannel("Cell114Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1572, + batteryCell115Voltage = new ModbusReadLongChannel("Cell115Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1573, + batteryCell116Voltage = new ModbusReadLongChannel("Cell116Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1574, + batteryCell117Voltage = new ModbusReadLongChannel("Cell117Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1575, + batteryCell118Voltage = new ModbusReadLongChannel("Cell18Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1576, + batteryCell119Voltage = new ModbusReadLongChannel("Cell119Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1577, + batteryCell120Voltage = new ModbusReadLongChannel("Cell120Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1578, + batteryCell121Voltage = new ModbusReadLongChannel("Cell121Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1579, + batteryCell122Voltage = new ModbusReadLongChannel("Cell122Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x157A, + batteryCell123Voltage = new ModbusReadLongChannel("Cell123Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x157B, + batteryCell124Voltage = new ModbusReadLongChannel("Cell124Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x157C, + batteryCell125Voltage = new ModbusReadLongChannel("Cell125Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x157D, + batteryCell126Voltage = new ModbusReadLongChannel("Cell126Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x157E, + batteryCell127Voltage = new ModbusReadLongChannel("Cell127Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x157F, + batteryCell128Voltage = new ModbusReadLongChannel("Cell128Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1580, + batteryCell129Voltage = new ModbusReadLongChannel("Cell129Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1581, + batteryCell130Voltage = new ModbusReadLongChannel("Cell130Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1582, + batteryCell131Voltage = new ModbusReadLongChannel("Cell131Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1583, + batteryCell132Voltage = new ModbusReadLongChannel("Cell132Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1584, + batteryCell133Voltage = new ModbusReadLongChannel("Cell133Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1585, + batteryCell134Voltage = new ModbusReadLongChannel("Cell134Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1586, + batteryCell135Voltage = new ModbusReadLongChannel("Cell135Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1587, + batteryCell136Voltage = new ModbusReadLongChannel("Cell136Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1588, + batteryCell137Voltage = new ModbusReadLongChannel("Cell137Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1589, + batteryCell138Voltage = new ModbusReadLongChannel("Cell138Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x158A, + batteryCell139Voltage = new ModbusReadLongChannel("Cell139Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x158B, + batteryCell140Voltage = new ModbusReadLongChannel("Cell140Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x158C, + batteryCell141Voltage = new ModbusReadLongChannel("Cell141Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x158D, + batteryCell142Voltage = new ModbusReadLongChannel("Cell142Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x158E, + batteryCell143Voltage = new ModbusReadLongChannel("Cell143Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x158F, + batteryCell144Voltage = new ModbusReadLongChannel("Cell144Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1590, + batteryCell145Voltage = new ModbusReadLongChannel("Cell145Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1591, + batteryCell146Voltage = new ModbusReadLongChannel("Cell146Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1592, + batteryCell147Voltage = new ModbusReadLongChannel("Cell147Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1593, + batteryCell148Voltage = new ModbusReadLongChannel("Cell148Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1594, + batteryCell149Voltage = new ModbusReadLongChannel("Cell149Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1595, + batteryCell150Voltage = new ModbusReadLongChannel("Cell150Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1596, + batteryCell151Voltage = new ModbusReadLongChannel("Cell151Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1597, + batteryCell152Voltage = new ModbusReadLongChannel("Cell152Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1598, + batteryCell153Voltage = new ModbusReadLongChannel("Cell153Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x1599, + batteryCell154Voltage = new ModbusReadLongChannel("Cell154Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x159A, + batteryCell155Voltage = new ModbusReadLongChannel("Cell155Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x159B, + batteryCell156Voltage = new ModbusReadLongChannel("Cell156Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x159C, + batteryCell157Voltage = new ModbusReadLongChannel("Cell157Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x159D, + batteryCell158Voltage = new ModbusReadLongChannel("Cell158Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x159E, + batteryCell159Voltage = new ModbusReadLongChannel("Cell159Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x159F, + batteryCell160Voltage = new ModbusReadLongChannel("Cell160Voltage", this).unit("mV") + )),// + new ModbusRegisterRange(0x15A0, // + new UnsignedWordElement(0x15A0, + batteryCell161Voltage = new ModbusReadLongChannel("Cell161Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15A1, + batteryCell162Voltage = new ModbusReadLongChannel("Cell162Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15A2, + batteryCell163Voltage = new ModbusReadLongChannel("Cell163Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15A3, + batteryCell164Voltage = new ModbusReadLongChannel("Cell164Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15A4, + batteryCell165Voltage = new ModbusReadLongChannel("Cell165Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15A5, + batteryCell166Voltage = new ModbusReadLongChannel("Cell166Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15A6, + batteryCell167Voltage = new ModbusReadLongChannel("Cell167Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15A7, + batteryCell168Voltage = new ModbusReadLongChannel("Cell168Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15A8, + batteryCell169Voltage = new ModbusReadLongChannel("Cell169Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15A9, + batteryCell170Voltage = new ModbusReadLongChannel("Cell170Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15AA, + batteryCell171Voltage = new ModbusReadLongChannel("Cell171Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15AB, + batteryCell172Voltage = new ModbusReadLongChannel("Cell172Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15AC, + batteryCell173Voltage = new ModbusReadLongChannel("Cell173Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15AD, + batteryCell174Voltage = new ModbusReadLongChannel("Cell174Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15AE, + batteryCell175Voltage = new ModbusReadLongChannel("Cell175Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15AF, + batteryCell176Voltage = new ModbusReadLongChannel("Cell176Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15B0, + batteryCell177Voltage = new ModbusReadLongChannel("Cell177Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15B1, + batteryCell178Voltage = new ModbusReadLongChannel("Cell178Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15B2, + batteryCell179Voltage = new ModbusReadLongChannel("Cell179Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15B3, + batteryCell180Voltage = new ModbusReadLongChannel("Cell180Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15B4, + batteryCell181Voltage = new ModbusReadLongChannel("Cell181Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15B5, + batteryCell182Voltage = new ModbusReadLongChannel("Cell182Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15B6, + batteryCell183Voltage = new ModbusReadLongChannel("Cell183Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15B7, + batteryCell184Voltage = new ModbusReadLongChannel("Cell184Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15B8, + batteryCell185Voltage = new ModbusReadLongChannel("Cell185Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15B9, + batteryCell186Voltage = new ModbusReadLongChannel("Cell186Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15BA, + batteryCell187Voltage = new ModbusReadLongChannel("Cell187Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15BB, + batteryCell188Voltage = new ModbusReadLongChannel("Cell188Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15BC, + batteryCell189Voltage = new ModbusReadLongChannel("Cell189Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15BD, + batteryCell190Voltage = new ModbusReadLongChannel("Cell190Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15BE, + batteryCell191Voltage = new ModbusReadLongChannel("Cell191Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15BF, + batteryCell192Voltage = new ModbusReadLongChannel("Cell192Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15C0, + batteryCell193Voltage = new ModbusReadLongChannel("Cell193Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15C1, + batteryCell194Voltage = new ModbusReadLongChannel("Cell194Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15C2, + batteryCell195Voltage = new ModbusReadLongChannel("Cell195Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15C3, + batteryCell196Voltage = new ModbusReadLongChannel("Cell196Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15C4, + batteryCell197Voltage = new ModbusReadLongChannel("Cell197Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15C5, + batteryCell198Voltage = new ModbusReadLongChannel("Cell198Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15C6, + batteryCell199Voltage = new ModbusReadLongChannel("Cell199Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15C7, + batteryCell200Voltage = new ModbusReadLongChannel("Cell200Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15C8, + batteryCell201Voltage = new ModbusReadLongChannel("Cell201Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15C9, + batteryCell202Voltage = new ModbusReadLongChannel("Cell202Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15CA, + batteryCell203Voltage = new ModbusReadLongChannel("Cell203Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15CB, + batteryCell204Voltage = new ModbusReadLongChannel("Cell204Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15CC, + batteryCell205Voltage = new ModbusReadLongChannel("Cell205Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15CD, + batteryCell206Voltage = new ModbusReadLongChannel("Cell206Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15CE, + batteryCell207Voltage = new ModbusReadLongChannel("Cell207Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15CF, + batteryCell208Voltage = new ModbusReadLongChannel("Cell208Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15D0, + batteryCell209Voltage = new ModbusReadLongChannel("Cell209Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15D1, + batteryCell210Voltage = new ModbusReadLongChannel("Cell210Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15D2, + batteryCell211Voltage = new ModbusReadLongChannel("Cell211Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15D3, + batteryCell212Voltage = new ModbusReadLongChannel("Cell212Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15D4, + batteryCell213Voltage = new ModbusReadLongChannel("Cell213Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15D5, + batteryCell214Voltage = new ModbusReadLongChannel("Cell214Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15D6, + batteryCell215Voltage = new ModbusReadLongChannel("Cell215Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15D7, + batteryCell216Voltage = new ModbusReadLongChannel("Cell216Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15D8, + batteryCell217Voltage = new ModbusReadLongChannel("Cell217Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15D9, + batteryCell218Voltage = new ModbusReadLongChannel("Cell218Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15DA, + batteryCell219Voltage = new ModbusReadLongChannel("Cell219Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15DB, + batteryCell220Voltage = new ModbusReadLongChannel("Cell220Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15DC, + batteryCell221Voltage = new ModbusReadLongChannel("Cell221Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15DD, + batteryCell222Voltage = new ModbusReadLongChannel("Cell222Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15DE, + batteryCell223Voltage = new ModbusReadLongChannel("Cell223Voltage", this).unit("mV") + ),// + new UnsignedWordElement(0x15DF, + batteryCell224Voltage = new ModbusReadLongChannel("Cell224Voltage", this).unit("mV") + ))); } @@ -538,6 +1451,11 @@ public StaticValueChannel capacity() { return capacity; } + @Override + public ThingStateChannels getStateChannel() { + return thingState; + } + // @IsChannel(id = "BatteryAccumulatedCharge") // public final ModbusReadChannel _batteryAccumulatedCharge = new OldModbusChannelBuilder().nature(this).unit("Wh") // .build(); diff --git a/edge/src/io/openems/impl/device/commercial/WarningCharger.java b/edge/src/io/openems/impl/device/commercial/WarningCharger.java new file mode 100644 index 00000000000..3f5cb977a56 --- /dev/null +++ b/edge/src/io/openems/impl/device/commercial/WarningCharger.java @@ -0,0 +1,57 @@ +package io.openems.impl.device.commercial; + +import io.openems.api.channel.thingstate.WarningEnum; + +public enum WarningCharger implements WarningEnum{ + CurrentSamplingChannelAbnormityOnHighVoltageSide(0), CurrentSamplingChannelAbnormityOnLowVoltageSide(1), BmsDCDC1EEPROMParametersOverRange(2),EEPROMParametersOverRange(3), UpdateEEPROMFailed(4), + ReadEEPROMFailed(5), CurrentSamplingChannelAbnormityBeforeInductance(6), ReactorPowerDecreaseCausedByOvertemperature(7), IGBTPowerDecreaseCausedByOvertemperature(8), + TemperatureChanel3PowerDecreaseCausedByOvertemperature(9), TemperatureChanel4PowerDecreaseCausedByOvertemperature(10), TemperatureChanel5PowerDecreaseCausedByOvertemperature(11), + TemperatureChanel6PowerDecreaseCausedByOvertemperature(12), TemperatureChanel7PowerDecreaseCausedByOvertemperature(13), TemperatureChanel8PowerDecreaseCausedByOvertemperature(14), + Fan1StopFailed(15), Fan2StopFailed(16), Fan3StopFailed(17), Fan4StopFailed(18), Fan1StartupFailed(19), Fan2StartupFailed(20), Fan3StartupFailed(21), Fan4StartupFailed(22), + HighVoltageSideOvervoltage(23), HighVoltageSideUndervoltage(24), HighVoltageSideVoltageChangeUnconventionally(25),CurrentAbnormityBeforeDCConverterWorkOnHighVoltageSide(26), + CurrentAbnormityBeforeDCConverterWorkOnLowVoltageSXide(27), InitialDutyRatioAbnormityBeforeDCConverterWork(28),VoltageAbnormityBeforeDCConverterWorkOnHighVoltageSide(29), + VoltageAbnormityBeforeDCConverterWorkOnLowVoltageSide(30), HighVoltageBreakerInspectionAbnormity(31),LowVoltageBreakerInspectionAbnormity(32), BsmDCDC5DCPrechargeContactorInspectionAbnormity(33), + DCPrechargeContactorOpenUnsuccessfully(34), DCMainContactorInspectionAbnormity(35),DCMainContactorOpenUnsuccessfully(36), OutputContactorCloseUnsuccessfully(37), OutputContactorOpenUnsuccessfully(38), + ACMainContactorCloseUnsuccessfully(39), ACMainContactorOpenUnsuccessfully(40),NegContactorOpenUnsuccessfully(41), NegContactorCloseUnsuccessfully(42), NegContactorStateAbnormal(43), + BsmDCDC1CurrentSamplingChannelAbnormityOnHighVoltageSide(44), BsmDCDC1CurrentSamplingChannelAbnormityOnLowVoltageSide(45), BsmDCDC1EEPROMParametersOverRange(46), BsmDCDC1UpdateEEPROMFailed(47), + BsmDCDC1ReadEEPROMFailed(48), BsmDCDC1CurrentSamplingChannelAbnormityBeforeInductance(49), BsmDCDC1ReactorPowerDecreaseCausedByOvertemperature(50), BsmDCDC1IGBTPowerDecreaseCausedByOvertemperature(51), + BsmDCDC1TemperatureChanel3PowerDecreaseCausedByOvertemperature(52), BsmDCDC1TemperatureChanel4PowerDecreaseCausedByOvertemperature(53), BsmDCDC1TemperatureChanel5PowerDecreaseCausedByOvertemperature(54), + BsmDCDC1TemperatureChanel6PowerDecreaseCausedByOvertemperature(55), BsmDCDC1TemperatureChanel7PowerDecreaseCausedByOvertemperature(56), BsmDCDC1TemperatureChanel8PowerDecreaseCausedByOvertemperature(57), + BsmDCDC1Fan1StopFailed(58), BsmDCDC1Fan2StopFailed(59), BsmDCDC1Fan3StopFailed(60), BsmDCDC1Fan4StopFailed(61), BsmDCDC1Fan1StartupFailed(62), BsmDCDC1Fan2StartupFailed(63), BsmDCDC1Fan3StartupFailed(64), + BsmDCDC1Fan4StartupFailed(65), BsmDCDC1HighVoltageSideOvervoltage(66), BsmDCDC1HighVoltageSideUndervoltage(67), BsmDCDC1HighVoltageSideVoltageChangeUnconventionally(68), BmsDCDC1CurrentAbnormityBeforeDCConverterWorkOnHighVoltageSide(69), + BmsDCDC1CurrentAbnormityBeforeDCConverterWorkOnLowVoltageSXide(70), BmsDCDC1InitialDutyRatioAbnormityBeforeDCConverterWork(71), BmsDCDC1VoltageAbnormityBeforeDCConverterWorkOnHighVoltageSide(72), + BmsDCDC1VoltageAbnormityBeforeDCConverterWorkOnLowVoltageSide(73), BmsDCDC1HighVoltageBreakerInspectionAbnormity(74), BmsDCDC1LowVoltageBreakerInspectionAbnormity(75), BmsDCDC1BsmDCDC5DCPrechargeContactorInspectionAbnormity(76), + BmsDCDC1DCPrechargeContactorOpenUnsuccessfully(77), BmsDCDC1DCMainContactorInspectionAbnormity(78), BmsDCDC1DCMainContactorOpenUnsuccessfully(79), BmsDCDC1OutputContactorCloseUnsuccessfully(80), + BmsDCDC1OutputContactorOpenUnsuccessfully(81), BmsDCDC1ACMainContactorCloseUnsuccessfully(82), BmsDCDC1ACMainContactorOpenUnsuccessfully(83), BmsDCDC1NegContactorOpenUnsuccessfully(84), + BmsDCDC1NegContactorCloseUnsuccessfully(85), BmsDCDC1NegContactorStateAbnormal(86), PvDCDCCurrentSamplingChannelAbnormityOnHighVoltageSide(87), PvDCDCCurrentSamplingChannelAbnormityOnLowVoltageSide(88), + PvDCDCEEPROMParametersOverRange(89), PvDCDCUpdateEEPROMFailed(90), PvDCDCReadEEPROMFailed(91), PvDCDCCurrentSamplingChannelAbnormityBeforeInductance(92), PvDCDCReactorPowerDecreaseCausedByOvertemperature(93), + PvDCDCIGBTPowerDecreaseCausedByOvertemperature(94), PvDCDCTemperatureChanel3PowerDecreaseCausedByOvertemperature(95), PvDCDCTemperatureChanel4PowerDecreaseCausedByOvertemperature(96), PvDCDCTemperatureChanel5PowerDecreaseCausedByOvertemperature(97), + PvDCDCTemperatureChanel6PowerDecreaseCausedByOvertemperature(98), PvDCDCTemperatureChanel7PowerDecreaseCausedByOvertemperature(99), PvDCDCTemperatureChanel8PowerDecreaseCausedByOvertemperature(100), + PvDCDCFan1StopFailed(101), PvDCDCFan2StopFailed(102), PvDCDCFan3StopFailed(103), PvDCDCFan4StopFailed(104), PvDCDCFan1StartupFailed(105), PvDCDCFan2StartupFailed(106), PvDCDCFan3StartupFailed(107), + PvDCDCFan4StartupFailed(108), PvDCDCHighVoltageSideOvervoltage(109), PvDCDCHighVoltageSideUndervoltage(110), PvDCDCHighVoltageSideVoltageChangeUnconventionally(111), PvDCDCCurrentAbnormityBeforeDCConverterWorkOnHighVoltageSide(112), + PvDCDCCurrentAbnormityBeforeDCConverterWorkOnLowVoltageSXide(113), PvDCDCInitialDutyRatioAbnormityBeforeDCConverterWork(114), PvDCDCVoltageAbnormityBeforeDCConverterWorkOnHighVoltageSide(115), + PvDCDCVoltageAbnormityBeforeDCConverterWorkOnLowVoltageSide(116), PvDCDCHighVoltageBreakerInspectionAbnormity(117), PvDCDCLowVoltageBreakerInspectionAbnormity(118), PvDCDCBsmDCDC5DCPrechargeContactorInspectionAbnormity(119), + PvDCDCDCPrechargeContactorOpenUnsuccessfully(120), PvDCDCDCMainContactorInspectionAbnormity(121), PvDCDCDCMainContactorOpenUnsuccessfully(122), PvDCDCOutputContactorCloseUnsuccessfully(123), PvDCDCOutputContactorOpenUnsuccessfully(124), + PvDCDCACMainContactorCloseUnsuccessfully(125), PvDCDCACMainContactorOpenUnsuccessfully(126), PvDCDCNegContactorOpenUnsuccessfully(127), PvDCDCNegContactorCloseUnsuccessfully(128), PvDCDCNegContactorStateAbnormal(129), + PvDCDC1CurrentSamplingChannelAbnormityOnHighVoltageSide(130), PvDCDC1CurrentSamplingChannelAbnormityOnLowVoltageSide(131), PvDCDC1EEPROMParametersOverRange(132), PvDCDC1UpdateEEPROMFailed(133), PvDCDC1ReadEEPROMFailed(134), + PvDCDC1CurrentSamplingChannelAbnormityBeforeInductance(135), PvDCDC1ReactorPowerDecreaseCausedByOvertemperature(136), PvDCDC1IGBTPowerDecreaseCausedByOvertemperature(137), PvDCDC1TemperatureChanel3PowerDecreaseCausedByOvertemperature(138), + PvDCDC1TemperatureChanel4PowerDecreaseCausedByOvertemperature(139), PvDCDC1TemperatureChanel5PowerDecreaseCausedByOvertemperature(140), PvDCDC1TemperatureChanel6PowerDecreaseCausedByOvertemperature(141), PvDCDC1TemperatureChanel7PowerDecreaseCausedByOvertemperature(142), + PvDCDC1TemperatureChanel8PowerDecreaseCausedByOvertemperature(143), PvDCDC1Fan1StopFailed(144), PvDCDC1Fan2StopFailed(145), PvDCDC1Fan3StopFailed(146), PvDCDC1Fan4StopFailed(147), PvDCDC1Fan1StartupFailed(148), PvDCDC1Fan2StartupFailed(149), + PvDCDC1Fan3StartupFailed(150), PvDCDC1Fan4StartupFailed(151), PvDCDC1HighVoltageSideOvervoltage(152), PvDCDC1HighVoltageSideUndervoltage(153), PvDCDC1HighVoltageSideVoltageChangeUnconventionally(154), PvDCDC1CurrentAbnormityBeforeDCConverterWorkOnHighVoltageSide(155), + PvDCDC1CurrentAbnormityBeforeDCConverterWorkOnLowVoltageSXide(156), PvDCDC1InitialDutyRatioAbnormityBeforeDCConverterWork(157), PvDCDC1VoltageAbnormityBeforeDCConverterWorkOnHighVoltageSide(158), PvDCDC1VoltageAbnormityBeforeDCConverterWorkOnLowVoltageSide(159), + PvDCDC1HighVoltageBreakerInspectionAbnormity(160), PvDCDC1LowVoltageBreakerInspectionAbnormity(161), PvDCDC1BsmDCDC5DCPrechargeContactorInspectionAbnormity(162), PvDCDC1DCPrechargeContactorOpenUnsuccessfully(163), PvDCDC1DCMainContactorInspectionAbnormity(164), + PvDCDC1DCMainContactorOpenUnsuccessfully(165), PvDCDC1OutputContactorCloseUnsuccessfully(166), PvDCDC1OutputContactorOpenUnsuccessfully(167), PvDCDC1ACMainContactorCloseUnsuccessfully(168), PvDCDC1ACMainContactorOpenUnsuccessfully(169), + PvDCDC1NegContactorOpenUnsuccessfully(170), PvDCDC1NegContactorCloseUnsuccessfully(171), PvDCDC1NegContactorStateAbnormal(172); + + + public final int value; + + private WarningCharger(int value) { + this.value = value; + } + + @Override + public int getValue() { + return this.value; + } +} diff --git a/edge/src/io/openems/impl/device/commercial/WarningEss.java b/edge/src/io/openems/impl/device/commercial/WarningEss.java new file mode 100644 index 00000000000..6e2d256a714 --- /dev/null +++ b/edge/src/io/openems/impl/device/commercial/WarningEss.java @@ -0,0 +1,29 @@ +package io.openems.impl.device.commercial; + +import io.openems.api.channel.thingstate.WarningEnum; + +public enum WarningEss implements WarningEnum { + EmergencyStop(0), KeyManualStop(1), TransformerPhaseBTemperatureSensorInvalidation(2), SDMemoryCardInvalidation(4), + InverterCommunicationAbnormity(5), BatteryStackCommunicationAbnormity(6), MultifunctionalAmmeterCommunicationAbnormity(7), + RemoteCommunicationAbnormity(8), PVDC1CommunicationAbnormity(9), PVDC2CommunicationAbnormity(10), TransformerSevereOvertemperature(11), + DCPrechargeContactorInspectionAbnormity(12), DCBreaker1InspectionAbnormity(13), DCBreaker2InspectionAbnormity(14), ACPrechargeContactorInspectionAbnormity(15), + ACMainontactorInspectionAbnormity(16), ACBreakerInspectionAbnormity(17), DCBreaker1CloseUnsuccessfully(18), DCBreaker2CloseUnsuccessfully(19), + ControlSignalCloseAbnormallyInspectedBySystem(20), ControlSignalOpenAbnormallyInspectedBySystem(21), NeutralWireContactorCloseUnsuccessfully(22), + NeutralWireContactorOpenUnsuccessfully(23), WorkDoorOpen(24), Emergency1Stop(25), ACBreakerCloseUnsuccessfully(26), ControlSwitchStop(27), GeneralOverload(28), + SevereOverload(29), BatteryCurrentOverLimit(30), PowerDecreaseCausedByOvertemperature(31), InverterGeneralOvertemperature(32), ACThreePhaseCurrentUnbalance(33), + RestoreFactorySettingUnsuccessfully(34), PoleBoardInvalidation(35), SelfInspectionFailed(36), ReceiveBMSFaultAndStop(37), RefrigerationEquipmentinvalidation(38), + LargeTemperatureDifferenceAmongIGBTThreePhases(39), EEPROMParametersOverRange(40), EEPROMParametersBackupFailed(41), DCBreakerCloseunsuccessfully(42), + CommunicationBetweenInverterAndBSMUDisconnected(43), CommunicationBetweenInverterAndMasterDisconnected(44), CommunicationBetweenInverterAndUCDisconnected(45), + BMSStartOvertimeControlledByPCS(46), BMSStopOvertimeControlledByPCS(47), SyncSignalInvalidation(48), SyncSignalContinuousCaputureFault(49), SyncSignalSeveralTimesCaputureFault(50); + + public final int value; + + private WarningEss(int value) { + this.value = value; + } + + @Override + public int getValue() { + return this.value; + } +} diff --git a/edge/src/io/openems/impl/device/custom/riedmann/Riedmann.java b/edge/src/io/openems/impl/device/custom/riedmann/Riedmann.java index 1aae8f47974..25c7be93058 100644 --- a/edge/src/io/openems/impl/device/custom/riedmann/Riedmann.java +++ b/edge/src/io/openems/impl/device/custom/riedmann/Riedmann.java @@ -15,7 +15,7 @@ public class Riedmann extends ModbusDevice { @ChannelInfo(title = "", type = RiedmannNatureImpl.class) - public final ConfigChannel device = new ConfigChannel("device", this); + public final ConfigChannel device = new ConfigChannel("device", this).addChangeListener(this); public Riedmann(Bridge parent) throws OpenemsException { super(parent); diff --git a/edge/src/io/openems/impl/device/custom/riedmann/RiedmannNatureImpl.java b/edge/src/io/openems/impl/device/custom/riedmann/RiedmannNatureImpl.java index d8e12bc555b..ee241701818 100644 --- a/edge/src/io/openems/impl/device/custom/riedmann/RiedmannNatureImpl.java +++ b/edge/src/io/openems/impl/device/custom/riedmann/RiedmannNatureImpl.java @@ -1,5 +1,6 @@ package io.openems.impl.device.custom.riedmann; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.doc.ThingInfo; import io.openems.api.exception.ConfigException; @@ -57,6 +58,7 @@ public class RiedmannNatureImpl extends ModbusDeviceNature implements RiedmannNa private ModbusWriteChannel setWaterLevelBorehole2Off; private ModbusWriteChannel setWaterLevelBorehole3On; private ModbusWriteChannel setWaterLevelBorehole3Off; + private ThingStateChannels thingState; @Override public ModbusReadChannel getWaterlevel() { @@ -260,6 +262,7 @@ public ModbusWriteChannel getSetWaterLevelBorehole3Off() { public RiedmannNatureImpl(String thingId, Device parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); } @Override @@ -343,7 +346,12 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { new SignedWordElement(75, // getWaterLevelBorehole3Off = new ModbusReadLongChannel("GetWaterLevelBorehole3Off", this)) // - )); + )); + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; } } diff --git a/edge/src/io/openems/impl/device/janitza/JanitzaUMG96RME.java b/edge/src/io/openems/impl/device/janitza/JanitzaUMG96RME.java index 1fcce77cae0..7a8168ad9a0 100644 --- a/edge/src/io/openems/impl/device/janitza/JanitzaUMG96RME.java +++ b/edge/src/io/openems/impl/device/janitza/JanitzaUMG96RME.java @@ -45,7 +45,7 @@ public JanitzaUMG96RME(Bridge parent) throws OpenemsException { * Config */ @ChannelInfo(title = "Meter", description = "Sets the meter nature.", type = JanitzaUMG96RMEMeter.class) - public final ConfigChannel meter = new ConfigChannel<>("meter", this); + public final ConfigChannel meter = new ConfigChannel("meter", this).addChangeListener(this); /* * Methods diff --git a/edge/src/io/openems/impl/device/janitza/JanitzaUMG96RMEMeter.java b/edge/src/io/openems/impl/device/janitza/JanitzaUMG96RMEMeter.java index 6cc44b58394..74e3a9b60b2 100644 --- a/edge/src/io/openems/impl/device/janitza/JanitzaUMG96RMEMeter.java +++ b/edge/src/io/openems/impl/device/janitza/JanitzaUMG96RMEMeter.java @@ -22,6 +22,7 @@ import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.meter.AsymmetricMeterNature; import io.openems.api.device.nature.meter.SymmetricMeterNature; @@ -37,11 +38,14 @@ @ThingInfo(title = "Janitza UMG96RM Meter") public class JanitzaUMG96RMEMeter extends ModbusDeviceNature implements SymmetricMeterNature, AsymmetricMeterNature { + private ThingStateChannels thingState; + /* * Constructors */ public JanitzaUMG96RMEMeter(String thingId, Device parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); } /* @@ -127,14 +131,14 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { new ModbusRegisterRange(800, // new FloatElement(800, // frequency = new ModbusReadLongChannel("Frequency", this).unit("mHz")) // - .multiplier(3), + .multiplier(3), new DummyElement(802, 807), new FloatElement(808, voltageL1 = new ModbusReadLongChannel("VoltageL1", this).unit("mV")) - .multiplier(3), + .multiplier(3), new FloatElement(810, voltageL2 = new ModbusReadLongChannel("VoltageL2", this).unit("mV")) - .multiplier(3), + .multiplier(3), new FloatElement(812, voltageL3 = new ModbusReadLongChannel("VoltageL3", this).unit("mV")) - .multiplier(3), + .multiplier(3), new DummyElement(814, 859), new FloatElement(860, // currentL1 = new ModbusReadLongChannel("CurrentL1", this).unit("mA")).multiplier(3), new FloatElement(862, // @@ -145,32 +149,32 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { current = new ModbusReadLongChannel("Current", this).unit("mA")).multiplier(3), new FloatElement(868, // activePowerL1 = new ModbusReadLongChannel("ActivePowerL1", this) // - .unit("W")), // + .unit("W")), // new FloatElement(870, // activePowerL2 = new ModbusReadLongChannel("ActivePowerL2", this) // - .unit("W")), // + .unit("W")), // new FloatElement(872, // activePowerL3 = new ModbusReadLongChannel("ActivePowerL3", this) // - .unit("W")), // + .unit("W")), // new FloatElement(874, // activePower = new ModbusReadLongChannel("ActivePower", this) // - .unit("W")), // + .unit("W")), // new FloatElement(876, // reactivePowerL1 = new ModbusReadLongChannel("ReactivePowerL1", this) // - .unit("Var")), // + .unit("Var")), // new FloatElement(878, // reactivePowerL2 = new ModbusReadLongChannel("ReactivePowerL2", this) // - .unit("Var")), // + .unit("Var")), // new FloatElement(880, // reactivePowerL3 = new ModbusReadLongChannel("ReactivePowerL3", this) // - .unit("Var")), // + .unit("Var")), // new FloatElement(882, // reactivePower = new ModbusReadLongChannel("ReactivePower", this) // - .unit("Var")), // + .unit("Var")), // new DummyElement(884, 889), new FloatElement(890, // apparentPower = new ModbusReadLongChannel("ApparentPower", this) // - .unit("VA")) // - )); + .unit("VA")) // + )); } @Override @@ -232,4 +236,9 @@ public ReadChannel voltageL2() { public ReadChannel voltageL3() { return voltageL3; } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } } diff --git a/edge/src/io/openems/impl/device/keba/Keba.java b/edge/src/io/openems/impl/device/keba/Keba.java index b4e1b66907d..6558ec81a34 100644 --- a/edge/src/io/openems/impl/device/keba/Keba.java +++ b/edge/src/io/openems/impl/device/keba/Keba.java @@ -57,7 +57,7 @@ public Keba(Bridge parent) throws OpenemsException { public ConfigChannel ip = new ConfigChannel("ip", this); @ChannelInfo(title = "evcs", description = "Sets the EVCS nature.", type = KebaEvcs.class) - public final ConfigChannel evcs = new ConfigChannel("evcs", this); + public final ConfigChannel evcs = new ConfigChannel("evcs", this).addChangeListener(this); /* * Methods diff --git a/edge/src/io/openems/impl/device/keba/KebaEvcs.java b/edge/src/io/openems/impl/device/keba/KebaEvcs.java index 436db9d500e..22cac9b8f51 100644 --- a/edge/src/io/openems/impl/device/keba/KebaEvcs.java +++ b/edge/src/io/openems/impl/device/keba/KebaEvcs.java @@ -20,6 +20,7 @@ *******************************************************************************/ package io.openems.impl.device.keba; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.nature.evcs.EvcsNature; import io.openems.api.doc.ThingInfo; import io.openems.api.exception.ConfigException; @@ -29,8 +30,11 @@ @ThingInfo(title = "KEBA KeContact EVCS") public class KebaEvcs extends KebaDeviceNature implements EvcsNature { + private ThingStateChannels thingState; + public KebaEvcs(String thingId, KebaDevice parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); } @Override @@ -38,4 +42,9 @@ public String toString() { return state.format() + ";" + plug.format() + ";current:" + currUser.format() + "|" + currHardware.format() + ";energy:" + energySession.format() + "|" + energyTotal.format(); } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } } diff --git a/edge/src/io/openems/impl/device/kmtronic/KMTronicRelay.java b/edge/src/io/openems/impl/device/kmtronic/KMTronicRelay.java index ad16eaa1a07..71b47108e9d 100644 --- a/edge/src/io/openems/impl/device/kmtronic/KMTronicRelay.java +++ b/edge/src/io/openems/impl/device/kmtronic/KMTronicRelay.java @@ -45,7 +45,7 @@ public KMTronicRelay(Bridge parent) throws OpenemsException { * Config */ @ChannelInfo(title = "Output", description = "Sets the output nature.", type = KMTronicRelayOutput.class) - public final ConfigChannel output = new ConfigChannel<>("output", this); + public final ConfigChannel output = new ConfigChannel("output", this).addChangeListener(this); /* * Methods diff --git a/edge/src/io/openems/impl/device/kmtronic/KMTronicRelayOutput.java b/edge/src/io/openems/impl/device/kmtronic/KMTronicRelayOutput.java index 769a86cf0a4..040b00017b2 100644 --- a/edge/src/io/openems/impl/device/kmtronic/KMTronicRelayOutput.java +++ b/edge/src/io/openems/impl/device/kmtronic/KMTronicRelayOutput.java @@ -20,6 +20,7 @@ *******************************************************************************/ package io.openems.impl.device.kmtronic; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.io.OutputNature; import io.openems.api.doc.ThingInfo; @@ -33,12 +34,15 @@ @ThingInfo(title = "KMTronic Relay board Output") public class KMTronicRelayOutput extends ModbusDeviceNature implements OutputNature { + private ThingStateChannels thingState; + /* * Constructors */ public KMTronicRelayOutput(String thingId, Device parent) throws ConfigException { super(thingId, parent); outputs = new ModbusCoilWriteChannel[8]; + this.thingState = new ThingStateChannels(this); } /* @@ -68,4 +72,9 @@ public ModbusCoilWriteChannel[] setOutput() { return outputs; } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/device/kmtronic/KMTronicRelayOutputRev1.java b/edge/src/io/openems/impl/device/kmtronic/KMTronicRelayOutputRev1.java index e5dadf7ddf4..92eff267394 100644 --- a/edge/src/io/openems/impl/device/kmtronic/KMTronicRelayOutputRev1.java +++ b/edge/src/io/openems/impl/device/kmtronic/KMTronicRelayOutputRev1.java @@ -20,6 +20,7 @@ *******************************************************************************/ package io.openems.impl.device.kmtronic; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.io.OutputNature; import io.openems.api.doc.ThingInfo; @@ -33,12 +34,15 @@ @ThingInfo(title = "KMTronic Relay board Output") public class KMTronicRelayOutputRev1 extends ModbusDeviceNature implements OutputNature { + private ThingStateChannels thingState; + /* * Constructors */ public KMTronicRelayOutputRev1(String thingId, Device parent) throws ConfigException { super(thingId, parent); outputs = new ModbusCoilWriteChannel[7]; + this.thingState = new ThingStateChannels(this); } /* @@ -67,4 +71,9 @@ public ModbusCoilWriteChannel[] setOutput() { return outputs; } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/device/kmtronic/KMTronicRelayRev1.java b/edge/src/io/openems/impl/device/kmtronic/KMTronicRelayRev1.java index f380c2a7bf4..4062af41254 100644 --- a/edge/src/io/openems/impl/device/kmtronic/KMTronicRelayRev1.java +++ b/edge/src/io/openems/impl/device/kmtronic/KMTronicRelayRev1.java @@ -45,7 +45,7 @@ public KMTronicRelayRev1(Bridge parent) throws OpenemsException { * Config */ @ChannelInfo(title = "Output", description = "Sets the output nature.", type = KMTronicRelayOutputRev1.class) - public final ConfigChannel output = new ConfigChannel<>("output", this); + public final ConfigChannel output = new ConfigChannel("output", this).addChangeListener(this); /* * Methods diff --git a/edge/src/io/openems/impl/device/mini/FaultEss.java b/edge/src/io/openems/impl/device/mini/FaultEss.java new file mode 100644 index 00000000000..7cb96a7ec7c --- /dev/null +++ b/edge/src/io/openems/impl/device/mini/FaultEss.java @@ -0,0 +1,28 @@ +package io.openems.impl.device.mini; + +import io.openems.api.channel.thingstate.FaultEnum; + +public enum FaultEss implements FaultEnum{ + ControlCurrentOverload100Percent(0), ControlCurrentOverload110Percent(1), ControlCurrentOverload150Percent(2), ControlCurrentOverload200Percent(3), + ControlCurrentOverload120Percent(4), ControlCurrentOverload300Percent(5), ControlTransientLoad300Percent(6), GridOverCurrent(7), LockingWaveformTooManyTimes(8), + InverterVoltageZeroDriftError(9), GridVoltageZeroDriftError(10), ControlCurrentZeroDriftError(11), InverterCurrentZeroDriftError(12), GridCurrentZeroDriftError(13), + PDPProtection(14), HardwareControlCurrentProtection(15), HardwareACVoltProtection(16), HardwareDCCurrentProtection(17), HardwareTemperatureProtection(18), + NoCapturingSignal(19), DCOvervoltage(20), DCDisconnected(21), InverterUndervoltage(22), InverterOvervoltage(23), CurrentSensorFail(24), VoltageSensorFail(25), + PowerUncontrollable(26), CurrentUncontrollable(27), FanError(28), PhaseLack(29), InverterRelayFault(30), GridRelayFault(31), ControlPanelOvertemp(32), PowerPanelOvertemp(33), + DCInputOvercurrent(34), CapacitorOvertemp(35), RadiatorOvertemp(36), TransformerOvertemp(37), CombinationCommError(38), EEPROMError(39), LoadCurrentZeroDriftError(40), + CurrentLimitRError(41), PhaseSyncError(42), ExternalPVCurrentZeroDriftError(43), ExternalGridCurrentZeroDriftError(44); + + + + + private final int value; + + private FaultEss(int value) { + this.value = value; + } + + @Override + public int getValue() { + return this.value; + } +} diff --git a/edge/src/io/openems/impl/device/mini/FeneconMini.java b/edge/src/io/openems/impl/device/mini/FeneconMini.java index 1a3e21a08bd..6bf6f34848f 100644 --- a/edge/src/io/openems/impl/device/mini/FeneconMini.java +++ b/edge/src/io/openems/impl/device/mini/FeneconMini.java @@ -45,7 +45,7 @@ public FeneconMini(Bridge parent) throws OpenemsException { * Config */ @ChannelInfo(title = "Ess", description = "Sets the Ess nature.", type = FeneconMiniEss.class) - public final ConfigChannel ess = new ConfigChannel<>("ess", this); + public final ConfigChannel ess = new ConfigChannel("ess", this).addChangeListener(this); /* * Methods diff --git a/edge/src/io/openems/impl/device/mini/FeneconMiniEss.java b/edge/src/io/openems/impl/device/mini/FeneconMiniEss.java index ffcf2de55af..d0978c67719 100644 --- a/edge/src/io/openems/impl/device/mini/FeneconMiniEss.java +++ b/edge/src/io/openems/impl/device/mini/FeneconMiniEss.java @@ -25,8 +25,8 @@ import io.openems.api.channel.ReadChannel; import io.openems.api.channel.StaticValueChannel; import io.openems.api.channel.StatusBitChannel; -import io.openems.api.channel.StatusBitChannels; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.ess.EssNature; import io.openems.api.device.nature.ess.SymmetricEssNature; @@ -35,6 +35,7 @@ import io.openems.api.exception.ConfigException; import io.openems.api.exception.InvalidValueException; import io.openems.core.utilities.ControllerUtils; +import io.openems.impl.protocol.modbus.ModbusBitWrappingChannel; import io.openems.impl.protocol.modbus.ModbusDeviceNature; import io.openems.impl.protocol.modbus.ModbusReadLongChannel; import io.openems.impl.protocol.modbus.ModbusWriteLongChannel; @@ -49,6 +50,8 @@ @ThingInfo(title = "FENECON Mini ESS") public class FeneconMiniEss extends ModbusDeviceNature implements SymmetricEssNature, RealTimeClockNature { + private ThingStateChannels thingState; + /* * Constructors */ @@ -60,6 +63,7 @@ public FeneconMiniEss(String thingId, Device parent) throws ConfigException { chargeSoc.updateValue((Integer) newValue.get() - 2, false); } }); + this.thingState = new ThingStateChannels(this); } /* @@ -82,7 +86,6 @@ public ConfigChannel chargeSoc() { * Inherited Channels */ // ESS - private StatusBitChannels warning; private ModbusReadLongChannel allowedCharge; private ModbusReadLongChannel allowedDischarge; private ReadChannel gridMode; @@ -150,11 +153,6 @@ public WriteChannel setReactivePower() { return setReactivePower; } - @Override - public StatusBitChannels warning() { - return warning; - } - @Override public ReadChannel allowedApparent() { return phaseAllowedApparent; @@ -226,35 +224,34 @@ public WriteChannel rtcSecond() { */ @Override protected ModbusProtocol defineModbusProtocol() throws ConfigException { - warning = new StatusBitChannels("Warning", this); ModbusProtocol protokol = new ModbusProtocol(new ModbusRegisterRange(100, // new UnsignedWordElement(100, // systemState = new ModbusReadLongChannel("SystemState", this) // - .label(0, STANDBY) // - .label(1, "Start Off-Grid") // - .label(2, START) // - .label(3, FAULT) // - .label(4, "Off-grid PV")), + .label(0, STANDBY) // + .label(1, "Start Off-Grid") // + .label(2, START) // + .label(3, FAULT) // + .label(4, "Off-grid PV")), new UnsignedWordElement(101, // controlMode = new ModbusReadLongChannel("ControlMode", this) // - .label(1, "Remote") // - .label(2, "Local")), // + .label(1, "Remote") // + .label(2, "Local")), // new DummyElement(102, 103), // new UnsignedDoublewordElement(104, // totalBatteryChargeEnergy = new ModbusReadLongChannel("TotalBatteryChargeEnergy", this) - .unit("Wh")), // + .unit("Wh")), // new UnsignedDoublewordElement(106, // totalBatteryDischargeEnergy = new ModbusReadLongChannel("TotalBatteryDischargeEnergy", this) - .unit("Wh")), // + .unit("Wh")), // new UnsignedWordElement(108, // batteryGroupState = new ModbusReadLongChannel("BatteryGroupState", this) // - .label(0, "Initial") // - .label(1, "Stop") // - .label(2, "Starting") // - .label(3, "Running") // - .label(4, "Stopping") // - .label(5, "Fail")), + .label(0, "Initial") // + .label(1, "Stop") // + .label(2, "Starting") // + .label(3, "Running") // + .label(4, "Stopping") // + .label(5, "Fail")), new UnsignedWordElement(109, // soc = new ModbusReadLongChannel("Soc", this).unit("%").interval(0, 100)), new UnsignedWordElement(110, // @@ -264,24 +261,26 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { new SignedWordElement(112, // batteryPower = new ModbusReadLongChannel("BatteryPower", this).unit("W")), new UnsignedWordElement(113, // - batteryGroupAlarm = new ModbusReadLongChannel("BatteryGroupAlarm", this) - .label(1, "Fail, The system should be stopped") // - .label(2, "Common low voltage alarm") // - .label(4, "Common high voltage alarm") // - .label(8, "Charging over current alarm") // - .label(16, "Discharging over current alarm") // - .label(32, "Over temperature alarm")// - .label(64, "Interal communication abnormal")), + new ModbusBitWrappingChannel("BatteryGroupAlarm" , this, this.thingState)// + .warningBit(0, WarningEss.FailTheSystemShouldBeStopped )// + .warningBit(1, WarningEss.CommonLowVoltageAlarm)// + .warningBit(2, WarningEss.CommonHighVoltageAlarm)// + .warningBit(3, WarningEss.ChargingOverCurrentAlarm)// + .warningBit(4, WarningEss.DischargingOverCurrentAlarm)// + .warningBit(5, WarningEss.OverTemperatureAlarm)// + .warningBit(6, WarningEss.InteralCommunicationAbnormal)// + ),// + new UnsignedWordElement(114, // pcsOperationState = new ModbusReadLongChannel("PcsOperationState", this) - .label(0, "Self-checking") // - .label(1, "Standby") // - .label(2, "Off grid PV") // - .label(3, "Off grid") // - .label(4, ON_GRID) // - .label(5, "Fail") // - .label(6, "bypass 1") // - .label(7, "bypass 2")), + .label(0, "Self-checking") // + .label(1, "Standby") // + .label(2, "Off grid PV") // + .label(3, "Off grid") // + .label(4, ON_GRID) // + .label(5, "Fail") // + .label(6, "bypass 1") // + .label(7, "bypass 2")), new DummyElement(115, 117), // new SignedWordElement(118, // current = new ModbusReadLongChannel("Current", this).unit("mA").multiplier(2)), @@ -300,75 +299,89 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { new UnsignedWordElement(142, // allowedDischarge = new ModbusReadLongChannel("AllowedDischarge", this).unit("W")), new DummyElement(143, 149), - new UnsignedWordElement(150, pcsAlarm1 = warning.channel(new StatusBitChannel("PcsAlarm1", this)// - .label(1, "Grid undervoltage") // - .label(2, "Grid overvoltage") // - .label(4, "Grid under frequency") // - .label(8, "Grid over frequency") // - .label(16, "Grid power supply off") // - .label(32, "Grid condition unmeet")// - .label(64, "DC under voltage")// - .label(128, "Input over resistance")// - .label(256, "Combination error")// - .label(512, "Comm with inverter error")// - .label(1024, "Tme error")// - )), new UnsignedWordElement(151, pcsAlarm2 = warning.channel(new StatusBitChannel("PcsAlarm2", this)// - )), new UnsignedWordElement(152, warning.channel(pcsFault1 = new StatusBitChannel("PcsFault1", this)// - .label(1, "Control current overload 100%")// - .label(2, "Control current overload 110%")// - .label(4, "Control current overload 150%")// - .label(8, "Control current overload 200%")// - .label(16, "Control current overload 120%")// - .label(32, "Control current overload 300%")// - .label(64, "Control transient load 300%")// - .label(128, "Grid over current")// - .label(256, "Locking waveform too many times")// - .label(512, "Inverter voltage zero drift error")// - .label(1024, "Grid voltage zero drift error")// - .label(2048, "Control current zero drift error")// - .label(4096, "Inverter current zero drift error")// - .label(8192, "Grid current zero drift error")// - .label(16384, "PDP protection")// - .label(32768, "Hardware control current protection")// - )), new UnsignedWordElement(153, warning.channel(pcsFault2 = new StatusBitChannel("PcsFault2", this)// - .label(1, "Hardware AC volt. protection")// - .label(2, "Hardware DC curr. protection")// - .label(4, "Hardware temperature protection")// - .label(8, "No capturing signal")// - .label(16, "DC overvoltage")// - .label(32, "DC disconnected")// - .label(64, "Inverter undervoltage")// - .label(128, "Inverter overvoltage")// - .label(256, "Current sensor fail")// - .label(512, "Voltage sensor fail")// - .label(1024, "Power uncontrollable")// - .label(2048, "Current uncontrollable")// - .label(4096, "Fan error")// - .label(8192, "Phase lack")// - .label(16384, "Inverter relay fault")// - .label(32768, "Grid relay fault")// - )), new UnsignedWordElement(154, warning.channel(pcsFault3 = new StatusBitChannel("PcsFault3", this)// - .label(1, "Control panel overtemp")// - .label(2, "Power panel overtemp")// - .label(4, "DC input overcurrent")// - .label(8, "Capacitor overtemp")// - .label(16, "Radiator overtemp")// - .label(32, "Transformer overtemp")// - .label(64, "Combination comm error")// - .label(128, "EEPROM error")// - .label(256, "Load current zero drift error")// - .label(512, "Current limit-R error")// - .label(1024, "Phase sync error")// - .label(2048, "External PV current zero drift error")// - .label(4096, "External grid current zero drift error")// - ))), // + new UnsignedWordElement(150,// + new ModbusBitWrappingChannel("PcsAlarm1" , this, this.thingState)// + .warningBit(0, WarningEss.GridUndervoltage)// + .warningBit(1, WarningEss.GridOvervoltage)// + .warningBit(2, WarningEss.GridUnderFrequency)// + .warningBit(3, WarningEss.GridOverFrequency)// + .warningBit(4, WarningEss.GridPowerSupplyOff)// + .warningBit(5, WarningEss.GridConditionUnmeet)// + .warningBit(6, WarningEss.DCUnderVoltage)// + .warningBit(7, WarningEss.InputOverResistance)// + .warningBit(8, WarningEss.CombinationError)// + .warningBit(9, WarningEss.CommWithInverterError)// + .warningBit(10,WarningEss.TmeError)// + ),// + + new UnsignedWordElement(151, + new ModbusBitWrappingChannel("PcsAlarm2", this, this.thingState)// + ), // + + new UnsignedWordElement(152, + new ModbusBitWrappingChannel("PcsFault1", this, this.thingState)// + .faultBit(0, FaultEss.ControlCurrentOverload100Percent)// + .faultBit(1, FaultEss.ControlCurrentOverload110Percent)// + .faultBit(2, FaultEss.ControlCurrentOverload150Percent)// + .faultBit(3, FaultEss.ControlCurrentOverload200Percent)// + .faultBit(4, FaultEss.ControlCurrentOverload120Percent)// + .faultBit(5, FaultEss.ControlCurrentOverload300Percent)// + .faultBit(6, FaultEss.ControlTransientLoad300Percent)// + .faultBit(7, FaultEss.GridOverCurrent)// + .faultBit(8, FaultEss.LockingWaveformTooManyTimes)// + .faultBit(9, FaultEss.InverterVoltageZeroDriftError)// + .faultBit(10,FaultEss.GridVoltageZeroDriftError)// + .faultBit(11,FaultEss.ControlCurrentZeroDriftError)// + .faultBit(12,FaultEss.InverterCurrentZeroDriftError)// + .faultBit(13,FaultEss.GridCurrentZeroDriftError)// + .faultBit(14, FaultEss.PDPProtection)// + .faultBit(15, FaultEss.HardwareControlCurrentProtection)// + ),// + + new UnsignedWordElement(153, // + new ModbusBitWrappingChannel("PcsFault2" , this, this.thingState)// + .faultBit(0, FaultEss.HardwareACVoltProtection)// + .faultBit(1, FaultEss.HardwareDCCurrentProtection)// + .faultBit(2, FaultEss.HardwareTemperatureProtection)// + .faultBit(3, FaultEss.NoCapturingSignal)// + .faultBit(4, FaultEss.DCOvervoltage)// + .faultBit(5, FaultEss.DCDisconnected)// + .faultBit(6, FaultEss.InverterUndervoltage)// + .faultBit(7, FaultEss.InverterOvervoltage)// + .faultBit(8, FaultEss.CurrentSensorFail)// + .faultBit(9, FaultEss.VoltageSensorFail)// + .faultBit(10,FaultEss.PowerUncontrollable)// + .faultBit(11,FaultEss.CurrentUncontrollable)// + .faultBit(12,FaultEss.FanError)// + .faultBit(13,FaultEss.PhaseLack)// + .faultBit(14,FaultEss.InverterRelayFault)// + .faultBit(15,FaultEss.GridRelayFault)// + ),// + + new UnsignedWordElement(154, // + new ModbusBitWrappingChannel("PcsFault3", this, this.thingState)// + .faultBit(0, FaultEss.ControlPanelOvertemp)// + .faultBit(1, FaultEss.PowerPanelOvertemp)// + .faultBit(2, FaultEss.DCInputOvercurrent)// + .faultBit(3, FaultEss.CapacitorOvertemp)// + .faultBit(4, FaultEss.RadiatorOvertemp)// + .faultBit(5, FaultEss.TransformerOvertemp)// + .faultBit(6, FaultEss.CombinationCommError)// + .faultBit(7, FaultEss.EEPROMError)// + .faultBit(8, FaultEss.LoadCurrentZeroDriftError)// + .faultBit(9, FaultEss.CurrentLimitRError)// + .faultBit(10,FaultEss.PhaseSyncError)// + .faultBit(11,FaultEss.ExternalPVCurrentZeroDriftError)// + .faultBit(12,FaultEss.ExternalGridCurrentZeroDriftError)// + )),// + new WriteableModbusRegisterRange(200, // new UnsignedWordElement(200, setWorkState = new ModbusWriteLongChannel("SetWorkState", this)// - .label(0, "Local control") // - .label(1, START) // "Remote control on grid starting" - .label(2, "Remote control off grid starting") // - .label(3, STOP)// - .label(4, "Emergency Stop"))), + .label(0, "Local control") // + .label(1, START) // "Remote control on grid starting" + .label(2, "Remote control off grid starting") // + .label(3, STOP)// + .label(4, "Emergency Stop"))), new WriteableModbusRegisterRange(201, // new SignedWordElement(201, setActivePower = new ModbusWriteLongChannel("SetActivePower", this).unit("W")), // @@ -384,28 +397,28 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { new WriteableModbusRegisterRange(30558, new UnsignedWordElement(30558, setSetupMode = new ModbusWriteLongChannel("SetSetupMode", this).label(0, EssNature.OFF) - .label(1, EssNature.ON))), + .label(1, EssNature.ON))), new WriteableModbusRegisterRange(30559, new UnsignedWordElement(30559, setPcsMode = new ModbusWriteLongChannel("SetPcsMode", this)// - .label(0, "Emergency")// - .label(1, "ConsumersPeakPattern")// - .label(2, "Economic")// - .label(3, "Eco")// - .label(4, "Debug")// - .label(5, "SmoothPv")// - .label(6, "Remote"))), + .label(0, "Emergency")// + .label(1, "ConsumersPeakPattern")// + .label(2, "Economic")// + .label(3, "Eco")// + .label(4, "Debug")// + .label(5, "SmoothPv")// + .label(6, "Remote"))), new ModbusRegisterRange(30157, new UnsignedWordElement(30157, setupMode = new ModbusReadLongChannel("SetupMode", this)// - .label(0, EssNature.OFF)// - .label(1, EssNature.ON)), + .label(0, EssNature.OFF)// + .label(1, EssNature.ON)), new UnsignedWordElement(30158, pcsMode = new ModbusReadLongChannel("PcsMode", this)// - .label(0, "Emergency")// - .label(1, "ConsumersPeakPattern")// - .label(2, "Economic")// - .label(3, "Eco")// - .label(4, "Debug")// - .label(5, "SmoothPv")// - .label(6, "Remote")))); + .label(0, "Emergency")// + .label(1, "ConsumersPeakPattern")// + .label(2, "Economic")// + .label(3, "Eco")// + .label(4, "Debug")// + .label(5, "SmoothPv")// + .label(6, "Remote")))); gridMode = new FunctionalReadChannel("GridMode", this, (channels) -> { ReadChannel state = channels[0]; try { @@ -447,4 +460,9 @@ public StaticValueChannel capacity() { return capacity; } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/device/mini/WarningEss.java b/edge/src/io/openems/impl/device/mini/WarningEss.java new file mode 100644 index 00000000000..acd33576da4 --- /dev/null +++ b/edge/src/io/openems/impl/device/mini/WarningEss.java @@ -0,0 +1,21 @@ +package io.openems.impl.device.mini; + +import io.openems.api.channel.thingstate.WarningEnum; + +public enum WarningEss implements WarningEnum{ + FailTheSystemShouldBeStopped(0), CommonLowVoltageAlarm(1), CommonHighVoltageAlarm(2), ChargingOverCurrentAlarm(3), + DischargingOverCurrentAlarm(4), OverTemperatureAlarm(5), InteralCommunicationAbnormal(6), GridUndervoltage(7), + GridOvervoltage(8), GridUnderFrequency(9), GridOverFrequency(10), GridPowerSupplyOff(11), GridConditionUnmeet(12), + DCUnderVoltage(13), InputOverResistance(14), CombinationError(15), CommWithInverterError(16), TmeError(17); + + public final int value; + + private WarningEss(int value) { + this.value = value; + } + + @Override + public int getValue() { + return this.value; + } +} diff --git a/edge/src/io/openems/impl/device/minireadonly/FaultEss.java b/edge/src/io/openems/impl/device/minireadonly/FaultEss.java new file mode 100644 index 00000000000..877cd7ad862 --- /dev/null +++ b/edge/src/io/openems/impl/device/minireadonly/FaultEss.java @@ -0,0 +1,27 @@ +package io.openems.impl.device.minireadonly; + +import io.openems.api.channel.thingstate.FaultEnum; + +public enum FaultEss implements FaultEnum +{ + + BECU1DischargeSevereOvercurrent(0), BECU1ChargeSevereOvercurrent(1), BECU1GeneralUndervoltage(2), BECU1SevereOvervoltage(3), BECU1GeneralOvervoltage(4), BECU1SevereUndervoltage(5), BECU1InsideCANBroken(6), + BECU1GeneralUndervoltageHighCurrentDischarge(7), BECU1BMUError(8), BECU1CurrentSamplingInvalidation(9), BECU1BatteryFail(10), BECU1TemperatureSamplingBroken(11), BECU1Contactor1TestBackIsAbnormalTurnOnAbnormity(12), + BECU1Contactor1TestBackIsAbnormalTurnOffAbnormity(13), BECU1Contactor2TestBackIsAbnormalTurnOnAbnormity(14), BECU1Contactor2TestBackIsAbnormalTurnOffAbnormity(15), BECU1SevereHighTemperatureFault(16), + BECU1HallInvalidation(17), BECU1ContactorInvalidation(18), BECU1OutsideCANBroken(19), BECU1CathodeContactorBroken(20), BECU2DischargeSevereOvercurrent(21), BECU2ChargeSevereOvercurrent(22), BECU2GeneralUndervoltage(23), + BECU2SevereOvervoltage(24), BECU2GeneralOvervoltage(25), BECU2SevereUndervoltage(26), BECU2InsideCANBroken(27), BECU2GeneralUndervoltageHighCurrentDischarge(28), BECU2BMUError(29), BECU2CurrentSamplingInvalidation(30), + BECU2BatteryFail(31), BECU2TemperatureSamplingBroken(32), BECU2Contactor1TestBackIsAbnormalTurnOnAbnormity(33), BECU2Contactor1TestBackIsAbnormalTurnOffAbnormity(34), BECU2Contactor2TestBackIsAbnormalTurnOnAbnormity(35), + BECU2Contactor2TestBackIsAbnormalTurnOffAbnormity(36), BECU2SevereHighTemperatureFault(37), BECU2HallInvalidation(38), BECU2ContactorInvalidation(39), BECU2OutsideCANBroken(40), BECU2CathodeContactorBroken(41), + NoAvailableBatteryGroup(42), StackGeneralLeakage(43), StackSevereLeakage(44), StackStartingFail(45), StackStoppingFail(46), BatteryProtection(47), StackAndGroup1CANCommunicationInterrupt(48), + StackAndGroup2CANCommunicationInterrupt(49); + private final int value; + + private FaultEss(int value) { + this.value = value; + } + + @Override + public int getValue() { + return this.value; + } +} diff --git a/edge/src/io/openems/impl/device/minireadonly/FeneconMini.java b/edge/src/io/openems/impl/device/minireadonly/FeneconMini.java index 3f4f7b3965a..7caf8685bba 100644 --- a/edge/src/io/openems/impl/device/minireadonly/FeneconMini.java +++ b/edge/src/io/openems/impl/device/minireadonly/FeneconMini.java @@ -29,6 +29,7 @@ import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; import io.openems.api.exception.OpenemsException; +import io.openems.impl.device.mini.FeneconMiniEss; import io.openems.impl.protocol.modbus.ModbusDevice; @ThingInfo(title = "FENECON Mini") @@ -45,18 +46,18 @@ public FeneconMini(Bridge parent) throws OpenemsException { * Config */ @ChannelInfo(title = "Ess", description = "Sets the Ess nature.", type = FeneconMiniEss.class) - public final ConfigChannel ess = new ConfigChannel<>("ess", this); + public final ConfigChannel ess = new ConfigChannel("ess", this).addChangeListener(this); @ChannelInfo(title = "GridMeter", description = "Sets the GridMeter nature.", type = FeneconMiniGridMeter.class) - public final ConfigChannel gridMeter = new ConfigChannel<>("gridMeter", this); + public final ConfigChannel gridMeter = new ConfigChannel("gridMeter", this).addChangeListener(this); @ChannelInfo(title = "ProductionMeter", description = "Sets the ProductionMeter nature.", type = FeneconMiniProductionMeter.class) - public final ConfigChannel productionMeter = new ConfigChannel<>("productionMeter", - this); + public final ConfigChannel productionMeter = new ConfigChannel("productionMeter", + this).addChangeListener(this); @ChannelInfo(title = "ConsumptionMeter", description = "Sets the ConsumptionMeter nature.", type = FeneconMiniConsumptionMeter.class) - public final ConfigChannel consumptionMeter = new ConfigChannel<>("consumptionMeter", - this); + public final ConfigChannel consumptionMeter = new ConfigChannel("consumptionMeter", + this).addChangeListener(this); /* * Methods diff --git a/edge/src/io/openems/impl/device/minireadonly/FeneconMiniConsumptionMeter.java b/edge/src/io/openems/impl/device/minireadonly/FeneconMiniConsumptionMeter.java index f8abdcd134d..5b1994d8e0b 100644 --- a/edge/src/io/openems/impl/device/minireadonly/FeneconMiniConsumptionMeter.java +++ b/edge/src/io/openems/impl/device/minireadonly/FeneconMiniConsumptionMeter.java @@ -3,6 +3,7 @@ import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.ReadChannel; import io.openems.api.channel.StaticValueChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.meter.SymmetricMeterNature; import io.openems.api.doc.ThingInfo; @@ -17,11 +18,14 @@ @ThingInfo(title = "FENECON Mini Consumption-Meter") public class FeneconMiniConsumptionMeter extends ModbusDeviceNature implements SymmetricMeterNature { + private ThingStateChannels thingState; + /* * Constructors */ public FeneconMiniConsumptionMeter(String thingId, Device parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); } /* @@ -96,8 +100,13 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { new ModbusRegisterRange(4005, // new UnsignedWordElement(4005, // this.activePower = new ModbusReadLongChannel("ActivePower", this).unit("W") - .ignore(55536l)))); + .ignore(55536l)))); return protocol; } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/device/minireadonly/FeneconMiniEss.java b/edge/src/io/openems/impl/device/minireadonly/FeneconMiniEss.java index f8f7cedecbc..a617b2a37c3 100644 --- a/edge/src/io/openems/impl/device/minireadonly/FeneconMiniEss.java +++ b/edge/src/io/openems/impl/device/minireadonly/FeneconMiniEss.java @@ -23,12 +23,13 @@ import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.ReadChannel; import io.openems.api.channel.StaticValueChannel; -import io.openems.api.channel.StatusBitChannels; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.ess.AsymmetricEssNature; import io.openems.api.doc.ThingInfo; import io.openems.api.exception.ConfigException; +import io.openems.impl.protocol.modbus.ModbusBitWrappingChannel; import io.openems.impl.protocol.modbus.ModbusDeviceNature; import io.openems.impl.protocol.modbus.ModbusReadLongChannel; import io.openems.impl.protocol.modbus.internal.DummyElement; @@ -40,6 +41,8 @@ @ThingInfo(title = "FENECON Mini ESS") public class FeneconMiniEss extends ModbusDeviceNature implements AsymmetricEssNature { + private ThingStateChannels thingState; + /* * Constructors */ @@ -51,6 +54,7 @@ public FeneconMiniEss(String thingId, Device parent) throws ConfigException { chargeSoc.updateValue((Integer) newValue.get() - 2, false); } }); + this.thingState = new ThingStateChannels(this); } /* @@ -85,8 +89,6 @@ public ConfigChannel chargeSoc() { private StaticValueChannel reactivePowerL1 = new StaticValueChannel("ReactivePowerL1", this, 0l); private StaticValueChannel reactivePowerL2 = new StaticValueChannel("ReactivePowerL2", this, 0l); private StaticValueChannel reactivePowerL3 = new StaticValueChannel("ReactivePowerL3", this, 0l); - private StatusBitChannels warning = new StatusBitChannels("Warning", this); - /* * This channels */ @@ -205,11 +207,6 @@ public ReadChannel maxNominalPower() { return null; } - @Override - public StatusBitChannels warning() { - return this.warning; - } - @Override public ReadChannel reactivePowerL1() { return this.reactivePowerL1; @@ -319,13 +316,71 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { new UnsignedWordElement(3004, // this.becu1Soc = new ModbusReadLongChannel("Becu1Soc", this)), new UnsignedWordElement(3005, // - this.becu1Alarm1 = new ModbusReadLongChannel("Becu1Alarm1", this)), + new ModbusBitWrappingChannel("BecuAlarm1" , this, this.thingState)// + .warningBit(0, WarningEss.BECU1GeneralChargeOverCurrentAlarm )// + .warningBit(1, WarningEss.BECU1GeneralDischargeOverCurrentAlarm )// + .warningBit(2, WarningEss.BECU1ChargeCurrentLimitAlarm)// + .warningBit(3, WarningEss.BECU1DischargeCurrentLimitAlarm)// + .warningBit(4, WarningEss.BECU1GeneralHighVoltageAlarm)// + .warningBit(5, WarningEss.BECU1GeneralLowVoltageAlarm)// + .warningBit(6, WarningEss.BECU1AbnormalVoltageChangeAlarm)// + .warningBit(7, WarningEss.BECU1GeneralHighTemperatureAlarm )// + .warningBit(8, WarningEss.BECU1GeneralLowTemperatureAlarm )// + .warningBit(9, WarningEss.BECU1AbnormalTemperatureChangeAlarm)// + .warningBit(10,WarningEss.BECU1SevereHighVoltageAlarm)// + .warningBit(11,WarningEss.BECU1SevereLowVoltageAlarm)// + .warningBit(12,WarningEss.BECU1SevereLowTemperatureAlarm)// + .warningBit(13,WarningEss.BECU1SeverveChargeOverCurrentAlarm )// + .warningBit(14,WarningEss.BECU1SeverveDischargeOverCurrentAlarm )// + .warningBit(15,WarningEss.BECU1AbnormalCellCapacityAlarm)// + ),// + new UnsignedWordElement(3006, // - this.becu1Alarm2 = new ModbusReadLongChannel("Becu1Alarm2", this)), + new ModbusBitWrappingChannel("BecuAlarm2" , this, this.thingState)// + .warningBit(0, WarningEss.BECU1BalancedSamplingAlarm)// + .warningBit(1, WarningEss.BECU1BalancedControlAlarm)// + .warningBit(2, WarningEss.BECU1HallSensorDoesNotWorkAccurately)// + .warningBit(4, WarningEss.BECU1Generalleakage)// + .warningBit(5, WarningEss.BECU1Severeleakage)// + .warningBit(6, WarningEss.BECU1Contactor1TurnOnAbnormity)// + .warningBit(7, WarningEss.BECU1Contactor1TurnOffAbnormity)// + .warningBit(8, WarningEss.BECU1Contactor2TurnOnAbnormity)// + .warningBit(9, WarningEss.BECU1Contactor2TurnOffAbnormity )// + .warningBit(10,WarningEss.BECU1Contactor4CheckAbnormity )// + .warningBit(11,WarningEss.BECU1ContactorCurrentUnsafe)// + .warningBit(12,WarningEss.BECU1Contactor5CheckAbnormity)// + .warningBit(13,WarningEss.BECU1HighVoltageOffset )// + .warningBit(14,WarningEss.BECU1LowVoltageOffset )// + .warningBit(15,WarningEss.BECU1HighTemperatureOffset )// + ),// + new UnsignedWordElement(3007, // - this.becu1Fault1 = new ModbusReadLongChannel("Becu1Fault1", this)), + new ModbusBitWrappingChannel("BecuFault1" , this, this.thingState)// + .faultBit(0, FaultEss.BECU1DischargeSevereOvercurrent)// + .faultBit(1, FaultEss.BECU1ChargeSevereOvercurrent)// + .faultBit(2, FaultEss.BECU1GeneralUndervoltage)// + .faultBit(3, FaultEss.BECU1SevereOvervoltage)// + .faultBit(4, FaultEss.BECU1GeneralOvervoltage)// + .faultBit(5, FaultEss.BECU1SevereUndervoltage)// + .faultBit(6, FaultEss.BECU1InsideCANBroken)// + .faultBit(7, FaultEss.BECU1GeneralUndervoltageHighCurrentDischarge)// + .faultBit(8, FaultEss.BECU1BMUError)// + .faultBit(9, FaultEss.BECU1CurrentSamplingInvalidation)// + .faultBit(10,FaultEss.BECU1BatteryFail)// + .faultBit(13,FaultEss.BECU1TemperatureSamplingBroken)// + .faultBit(14,FaultEss.BECU1Contactor1TestBackIsAbnormalTurnOnAbnormity)// + .faultBit(15,FaultEss.BECU1Contactor1TestBackIsAbnormalTurnOffAbnormity)// + ),// new UnsignedWordElement(3008, // - this.becu1Fault2 = new ModbusReadLongChannel("Becu1Fault2", this)), + new ModbusBitWrappingChannel("BecuFault2" , this, this.thingState)// + .faultBit(0, FaultEss.BECU1Contactor2TestBackIsAbnormalTurnOnAbnormity)// + .faultBit(1, FaultEss.BECU1Contactor2TestBackIsAbnormalTurnOffAbnormity)// + .faultBit(2, FaultEss.BECU1SevereHighTemperatureFault)// + .faultBit(9, FaultEss.BECU1HallInvalidation)// + .faultBit(10,FaultEss.BECU1ContactorInvalidation)// + .faultBit(12,FaultEss.BECU1OutsideCANBroken)// + .faultBit(13,FaultEss.BECU1CathodeContactorBroken)// + ),// new UnsignedWordElement(3009, // this.becu1Version = new ModbusReadLongChannel("Becu1Version", this)), new DummyElement(3010, 3011), // @@ -357,13 +412,69 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { new UnsignedWordElement(3204, // this.becu2Soc = new ModbusReadLongChannel("Becu2Soc", this)), new UnsignedWordElement(3205, // - this.becu2Alarm1 = new ModbusReadLongChannel("Becu2Alarm1", this)), + new ModbusBitWrappingChannel("Becu2Alarm1" , this, this.thingState)// + .warningBit(0, WarningEss.BECU2GeneralChargeOverCurrentAlarm )// + .warningBit(1, WarningEss.BECU2GeneralDischargeOverCurrentAlarm )// + .warningBit(2, WarningEss.BECU2ChargeCurrentLimitAlarm)// + .warningBit(3, WarningEss.BECU2DischargeCurrentLimitAlarm)// + .warningBit(4, WarningEss.BECU2GeneralHighVoltageAlarm)// + .warningBit(5, WarningEss.BECU2GeneralLowVoltageAlarm)// + .warningBit(6, WarningEss.BECU2AbnormalVoltageChangeAlarm)// + .warningBit(7, WarningEss.BECU2GeneralHighTemperatureAlarm )// + .warningBit(8, WarningEss.BECU2GeneralLowTemperatureAlarm )// + .warningBit(9, WarningEss.BECU2AbnormalTemperatureChangeAlarm)// + .warningBit(10,WarningEss.BECU2SevereHighVoltageAlarm)// + .warningBit(11,WarningEss.BECU2SevereLowVoltageAlarm)// + .warningBit(12,WarningEss.BECU2SevereLowTemperatureAlarm)// + .warningBit(13,WarningEss.BECU2SeverveChargeOverCurrentAlarm )// + .warningBit(14,WarningEss.BECU2SeverveDischargeOverCurrentAlarm )// + .warningBit(15,WarningEss.BECU2AbnormalCellCapacityAlarm)// + ),// new UnsignedWordElement(3206, // - this.becu2Alarm2 = new ModbusReadLongChannel("Becu2Alarm2", this)), + new ModbusBitWrappingChannel("Becu2Alarm2" , this, this.thingState)// + .warningBit(0, WarningEss.BECU2BalancedSamplingAlarm)// + .warningBit(1, WarningEss.BECU2BalancedControlAlarm)// + .warningBit(2, WarningEss.BECU2HallSensorDoesNotWorkAccurately)// + .warningBit(4, WarningEss.BECU2Generalleakage)// + .warningBit(5, WarningEss.BECU2Severeleakage)// + .warningBit(6, WarningEss.BECU2Contactor1TurnOnAbnormity)// + .warningBit(7, WarningEss.BECU2Contactor1TurnOffAbnormity)// + .warningBit(8, WarningEss.BECU2Contactor2TurnOnAbnormity)// + .warningBit(9, WarningEss.BECU2Contactor2TurnOffAbnormity )// + .warningBit(10,WarningEss.BECU2Contactor4CheckAbnormity )// + .warningBit(11,WarningEss.BECU2ContactorCurrentUnsafe)// + .warningBit(12,WarningEss.BECU2Contactor5CheckAbnormity)// + .warningBit(13,WarningEss.BECU2HighVoltageOffset )// + .warningBit(14,WarningEss.BECU2LowVoltageOffset )// + .warningBit(15,WarningEss.BECU2HighTemperatureOffset )// + ),// new UnsignedWordElement(3207, // - this.becu2Fault1 = new ModbusReadLongChannel("Becu2Fault1", this)), + new ModbusBitWrappingChannel("Becu2Fault1" , this, this.thingState)// + .faultBit(0, FaultEss.BECU2DischargeSevereOvercurrent)// + .faultBit(1, FaultEss.BECU2ChargeSevereOvercurrent)// + .faultBit(2, FaultEss.BECU2GeneralUndervoltage)// + .faultBit(3, FaultEss.BECU2SevereOvervoltage)// + .faultBit(4, FaultEss.BECU2GeneralOvervoltage)// + .faultBit(5, FaultEss.BECU2SevereUndervoltage)// + .faultBit(6, FaultEss.BECU2InsideCANBroken)// + .faultBit(7, FaultEss.BECU2GeneralUndervoltageHighCurrentDischarge)// + .faultBit(8, FaultEss.BECU2BMUError)// + .faultBit(9, FaultEss.BECU2CurrentSamplingInvalidation)// + .faultBit(10,FaultEss.BECU2BatteryFail)// + .faultBit(13,FaultEss.BECU2TemperatureSamplingBroken)// + .faultBit(14,FaultEss.BECU2Contactor1TestBackIsAbnormalTurnOnAbnormity)// + .faultBit(15,FaultEss.BECU2Contactor1TestBackIsAbnormalTurnOffAbnormity)// + ),// new UnsignedWordElement(3208, // - this.becu2Fault2 = new ModbusReadLongChannel("Becu2Fault2", this)), + new ModbusBitWrappingChannel("Becu2Fault2" , this, this.thingState)// + .faultBit(0, FaultEss.BECU2Contactor2TestBackIsAbnormalTurnOnAbnormity)// + .faultBit(1, FaultEss.BECU2Contactor2TestBackIsAbnormalTurnOffAbnormity)// + .faultBit(2, FaultEss.BECU2SevereHighTemperatureFault)// + .faultBit(9, FaultEss.BECU2HallInvalidation)// + .faultBit(10,FaultEss.BECU2ContactorInvalidation)// + .faultBit(12,FaultEss.BECU2OutsideCANBroken)// + .faultBit(13,FaultEss.BECU2CathodeContactorBroken)// + ),// new UnsignedWordElement(3209, // this.becu2Version = new ModbusReadLongChannel("Becu2Version", this)), new DummyElement(3210, 3211), // @@ -404,15 +515,63 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { new UnsignedWordElement(4807, // this.becuWorkState = new ModbusReadLongChannel("BecuWorkState", this)), new UnsignedWordElement(4808, // - this.becuFault1 = new ModbusReadLongChannel("BecuFault1", this)), + new ModbusBitWrappingChannel("BecuFault1", this, this.thingState)// + .faultBit(0, FaultEss.NoAvailableBatteryGroup)// + .faultBit(1, FaultEss.StackGeneralLeakage)// + .faultBit(2, FaultEss.StackSevereLeakage)// + .faultBit(3, FaultEss.StackStartingFail)// + .faultBit(4, FaultEss.StackStoppingFail)// + .faultBit(9, FaultEss.BatteryProtection)// + ),// new UnsignedWordElement(4809, // - this.becuFault2 = new ModbusReadLongChannel("BecuFault2", this)), + new ModbusBitWrappingChannel("BecuFault2" , this, this.thingState)// + .faultBit(0, FaultEss.StackAndGroup1CANCommunicationInterrupt)// + .faultBit(1, FaultEss.StackAndGroup2CANCommunicationInterrupt)// + ),// new UnsignedWordElement(4810, // - this.becuAlarm1 = new ModbusReadLongChannel("BecuAlarm1", this)), + new ModbusBitWrappingChannel("BecuAlarm2" , this, this.thingState)// + .warningBit(0, WarningEss.GeneralOvercurrentAlarmAtCellStackCharge)// + .warningBit(1, WarningEss.GeneralOvercurrentAlarmAtCellStackDischarge)// + .warningBit(2, WarningEss.CurrentLimitAlarmAtCellStackCharge)// + .warningBit(3, WarningEss.CurrentLimitAlarmAtCellStackDischarge)// + .warningBit(4, WarningEss.GeneralCellStackHighVoltageAlarm)// + .warningBit(5, WarningEss.GeneralCellStackLowVoltageAlarm)// + .warningBit(6, WarningEss.AbnormalCellStackVoltageChangeAlarm)// + .warningBit(7, WarningEss.GeneralCellStackHighTemperatureAlarm)// + .warningBit(8, WarningEss.GeneralCellStackLowTemperatureAlarm)// + .warningBit(9, WarningEss.AbnormalCellStackTemperatureChangeAlarm)// + .warningBit(10,WarningEss.SevereCellStackHighVoltageAlarm)// + .warningBit(11,WarningEss.SevereCellStackLowVoltageAlarm)// + .warningBit(12,WarningEss.SevereCellStackLowTemperatureAlarm)// + .warningBit(13,WarningEss.SeverveOverCurrentAlarmAtCellStackDharge)// + .warningBit(14,WarningEss.SeverveOverCurrentAlarmAtCellStackDischarge)// + .warningBit(15,WarningEss.AbnormalCellStackCapacityAlarm)// + ),// new UnsignedWordElement(4811, // - this.becuAlarm2 = new ModbusReadLongChannel("BecuAlarm2", this)), + new ModbusBitWrappingChannel("BecuAlarm2" , this, this.thingState)// + .warningBit(0, WarningEss.TheParameterOfEEPROMInCellStackLoseEffectiveness)// + .warningBit(1, WarningEss.IsolatingSwitchInConfluenceArkBreak)// + .warningBit(2, WarningEss.TheCommunicationBetweenCellStackAndTemperatureOfCollectorBreak)// + .warningBit(3, WarningEss.TheTemperatureOfCollectorFail)// + .warningBit(4, WarningEss.HallSensorDoNotWorkAccurately)// + .warningBit(5, WarningEss.TheCommunicationOfPCSBreak)// + .warningBit(6, WarningEss.AdvancedChargingOrMainContactorCloseAbnormally)// + .warningBit(7, WarningEss.AbnormalSampledVoltage)// + .warningBit(8, WarningEss.AbnormalAdvancedContactorOrAbnormalRS485GalleryOfPCS)// + .warningBit(9, WarningEss.AbnormalMainContactor)// + .warningBit(10,WarningEss.GeneralCellStackLeakage)// + .warningBit(11,WarningEss.SevereCellStackLeakage)// + .warningBit(12,WarningEss.SmokeAlarm)// + .warningBit(13,WarningEss.TheCommunicationWireToAmmeterBreak)// + .warningBit(14,WarningEss.TheCommunicationWireToDredBreak)// + ),// new UnsignedWordElement(4812, // this.soc = new ModbusReadLongChannel("Soc", this).unit("%")))); return protocol; } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } } diff --git a/edge/src/io/openems/impl/device/minireadonly/FeneconMiniGridMeter.java b/edge/src/io/openems/impl/device/minireadonly/FeneconMiniGridMeter.java index 55eb43e0937..f40ecf25b38 100644 --- a/edge/src/io/openems/impl/device/minireadonly/FeneconMiniGridMeter.java +++ b/edge/src/io/openems/impl/device/minireadonly/FeneconMiniGridMeter.java @@ -3,6 +3,7 @@ import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.ReadChannel; import io.openems.api.channel.StaticValueChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.meter.SymmetricMeterNature; import io.openems.api.doc.ThingInfo; @@ -17,11 +18,14 @@ @ThingInfo(title = "FENECON Mini Grid-Meter") public class FeneconMiniGridMeter extends ModbusDeviceNature implements SymmetricMeterNature { + private ThingStateChannels thingState; + /* * Constructors */ public FeneconMiniGridMeter(String thingId, Device parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); } /* @@ -93,16 +97,22 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { ModbusProtocol protocol = new ModbusProtocol( // new ModbusRegisterRange(4004, // new SignedWordElement(4004, // - this.activePower = new ModbusReadLongChannel("ActivePower", this).unit("W").negate())), + this.activePower = new ModbusReadLongChannel("ActivePower", this).unit("W").negate() + .ignore(-10000l))), new ModbusRegisterRange(5003, // new UnsignedDoublewordElement(5003, // this.sellToGridEnergy = new ModbusReadLongChannel("SellToGridEnergy", this).unit("Wh") - .multiplier(2)), + .multiplier(2)), new UnsignedDoublewordElement(5005, // this.buyFromGridEnergy = new ModbusReadLongChannel("BuyFromGridEnergy", this).unit("Wh") - .multiplier(2)))); + .multiplier(2)))); return protocol; } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/device/minireadonly/FeneconMiniProductionMeter.java b/edge/src/io/openems/impl/device/minireadonly/FeneconMiniProductionMeter.java index 2bccf623868..eb310344a43 100644 --- a/edge/src/io/openems/impl/device/minireadonly/FeneconMiniProductionMeter.java +++ b/edge/src/io/openems/impl/device/minireadonly/FeneconMiniProductionMeter.java @@ -3,6 +3,7 @@ import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.ReadChannel; import io.openems.api.channel.StaticValueChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.meter.SymmetricMeterNature; import io.openems.api.doc.ThingInfo; @@ -17,11 +18,14 @@ @ThingInfo(title = "FENECON Mini Production-Meter") public class FeneconMiniProductionMeter extends ModbusDeviceNature implements SymmetricMeterNature { + private ThingStateChannels thingState; + /* * Constructors */ public FeneconMiniProductionMeter(String thingId, Device parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); } /* @@ -99,4 +103,9 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { return protocol; } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/device/minireadonly/WarningEss.java b/edge/src/io/openems/impl/device/minireadonly/WarningEss.java new file mode 100644 index 00000000000..7031834556d --- /dev/null +++ b/edge/src/io/openems/impl/device/minireadonly/WarningEss.java @@ -0,0 +1,38 @@ +package io.openems.impl.device.minireadonly; + +import io.openems.api.channel.thingstate.WarningEnum; + +public enum WarningEss implements WarningEnum +{ + BECU1GeneralChargeOverCurrentAlarm(0), BECU1GeneralDischargeOverCurrentAlarm(1), BECU1ChargeCurrentLimitAlarm(2), BECU1DischargeCurrentLimitAlarm(3), + BECU1GeneralHighVoltageAlarm(4), BECU1GeneralLowVoltageAlarm(5), BECU1AbnormalVoltageChangeAlarm(6), BECU1GeneralHighTemperatureAlarm(7),BECU1GeneralLowTemperatureAlarm(8), + BECU1AbnormalTemperatureChangeAlarm(9), BECU1SevereHighVoltageAlarm(10), BECU1SevereLowVoltageAlarm(11),BECU1SevereLowTemperatureAlarm(12), BECU1SeverveChargeOverCurrentAlarm(13), + BECU1SeverveDischargeOverCurrentAlarm(14), BECU1AbnormalCellCapacityAlarm(15), BECU1BalancedSamplingAlarm(16), BECU1BalancedControlAlarm(17), BECU1HallSensorDoesNotWorkAccurately(18), + BECU1Generalleakage(19), BECU1Severeleakage(20), BECU1Contactor1TurnOnAbnormity(21), BECU1Contactor1TurnOffAbnormity(22), BECU1Contactor2TurnOnAbnormity(23), BECU1Contactor2TurnOffAbnormity(24), + BECU1Contactor4CheckAbnormity(25), BECU1ContactorCurrentUnsafe(26), BECU1Contactor5CheckAbnormity(27), BECU1HighVoltageOffset(28), BECU1LowVoltageOffset(29), BECU1HighTemperatureOffset(30), + BECU2GeneralChargeOverCurrentAlarm(31), BECU2GeneralDischargeOverCurrentAlarm(32), BECU2ChargeCurrentLimitAlarm(33), BECU2DischargeCurrentLimitAlarm(34), BECU2GeneralHighVoltageAlarm(35), + BECU2GeneralLowVoltageAlarm(36), BECU2AbnormalVoltageChangeAlarm(37), BECU2GeneralHighTemperatureAlarm(38), BECU2GeneralLowTemperatureAlarm(39), BECU2AbnormalTemperatureChangeAlarm(40), + BECU2SevereHighVoltageAlarm(41), BECU2SevereLowVoltageAlarm(42), BECU2SevereLowTemperatureAlarm(43), BECU2SeverveChargeOverCurrentAlarm(44), BECU2SeverveDischargeOverCurrentAlarm(45), + BECU2AbnormalCellCapacityAlarm(46), BECU2BalancedSamplingAlarm(47), BECU2BalancedControlAlarm(48), BECU2HallSensorDoesNotWorkAccurately(49), BECU2Generalleakage(50), BECU2Severeleakage(51), + BECU2Contactor1TurnOnAbnormity(52), BECU2Contactor1TurnOffAbnormity(53), BECU2Contactor2TurnOnAbnormity(54), BECU2Contactor2TurnOffAbnormity(55), BECU2Contactor4CheckAbnormity(56), + BECU2ContactorCurrentUnsafe(57), BECU2Contactor5CheckAbnormity(58), BECU2HighVoltageOffset(59), BECU2LowVoltageOffset(60), BECU2HighTemperatureOffset(61), GeneralOvercurrentAlarmAtCellStackCharge(62), + GeneralOvercurrentAlarmAtCellStackDischarge(63), CurrentLimitAlarmAtCellStackCharge(64), CurrentLimitAlarmAtCellStackDischarge(65), GeneralCellStackHighVoltageAlarm(66), GeneralCellStackLowVoltageAlarm(67), + AbnormalCellStackVoltageChangeAlarm(68), GeneralCellStackHighTemperatureAlarm(69), GeneralCellStackLowTemperatureAlarm(70), AbnormalCellStackTemperatureChangeAlarm(71), SevereCellStackHighVoltageAlarm(72), + SevereCellStackLowVoltageAlarm(73), SevereCellStackLowTemperatureAlarm(74), SeverveOverCurrentAlarmAtCellStackDharge(75), SeverveOverCurrentAlarmAtCellStackDischarge(76), AbnormalCellStackCapacityAlarm(77), + TheParameterOfEEPROMInCellStackLoseEffectiveness(78), IsolatingSwitchInConfluenceArkBreak(79), TheCommunicationBetweenCellStackAndTemperatureOfCollectorBreak(80), TheTemperatureOfCollectorFail(81), + HallSensorDoNotWorkAccurately(82), TheCommunicationOfPCSBreak(83), AdvancedChargingOrMainContactorCloseAbnormally(84), AbnormalSampledVoltage(85), AbnormalAdvancedContactorOrAbnormalRS485GalleryOfPCS(86), + AbnormalMainContactor(87), GeneralCellStackLeakage(88), SevereCellStackLeakage(89), SmokeAlarm(90), TheCommunicationWireToAmmeterBreak(91), TheCommunicationWireToDredBreak(92); + + + + public final int value; + + private WarningEss(int value) { + this.value = value; + } + + @Override + public int getValue() { + return this.value; + } +} diff --git a/edge/src/io/openems/impl/device/pqplus/PqPlusUMD97.java b/edge/src/io/openems/impl/device/pqplus/PqPlusUMD97.java index 8a1ae0c1be2..e902deacf8f 100644 --- a/edge/src/io/openems/impl/device/pqplus/PqPlusUMD97.java +++ b/edge/src/io/openems/impl/device/pqplus/PqPlusUMD97.java @@ -45,7 +45,7 @@ public PqPlusUMD97(Bridge parent) throws OpenemsException { * Config */ @ChannelInfo(title = "Meter", description = "Sets the meter nature.", type = PqPlusUMD97Meter.class) - public final ConfigChannel meter = new ConfigChannel<>("meter", this); + public final ConfigChannel meter = new ConfigChannel("meter", this).addChangeListener(this); /* * Methods diff --git a/edge/src/io/openems/impl/device/pqplus/PqPlusUMD97Meter.java b/edge/src/io/openems/impl/device/pqplus/PqPlusUMD97Meter.java index 993ce8014d2..e967d40329f 100644 --- a/edge/src/io/openems/impl/device/pqplus/PqPlusUMD97Meter.java +++ b/edge/src/io/openems/impl/device/pqplus/PqPlusUMD97Meter.java @@ -22,6 +22,7 @@ import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.meter.SymmetricMeterNature; import io.openems.api.doc.ThingInfo; @@ -36,11 +37,14 @@ @ThingInfo(title = "PQ Plus UMD 97 Meter") public class PqPlusUMD97Meter extends ModbusDeviceNature implements SymmetricMeterNature { + private ThingStateChannels thingState; + /* * Constructors */ public PqPlusUMD97Meter(String thingId, Device parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); } /* @@ -165,14 +169,19 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { reactivePower = new ModbusReadLongChannel("ReactivePower", this) // .unit("Var")), // new FloatElement(19044, // - cosPhiL1 = new ModbusReadLongChannel("CosPhiL1", this)), // + cosPhiL1 = new ModbusReadLongChannel("CosPhiL1", this)).multiplier(2), // new FloatElement(19046, // - cosPhiL2 = new ModbusReadLongChannel("CosPhiL2", this)), // + cosPhiL2 = new ModbusReadLongChannel("CosPhiL2", this)).multiplier(2), // new FloatElement(19048, // - cosPhiL3 = new ModbusReadLongChannel("CosPhiL3", this)), // + cosPhiL3 = new ModbusReadLongChannel("CosPhiL3", this)).multiplier(2), // new FloatElement(19050, // frequency = new ModbusReadLongChannel("Frequency", this).unit("mHz")) // .multiplier(3))); } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/device/pro/FaultEss.java b/edge/src/io/openems/impl/device/pro/FaultEss.java new file mode 100644 index 00000000000..91155a0b0cd --- /dev/null +++ b/edge/src/io/openems/impl/device/pro/FaultEss.java @@ -0,0 +1,21 @@ +package io.openems.impl.device.pro; + +import io.openems.api.channel.thingstate.FaultEnum; + +public enum FaultEss implements FaultEnum { + ControlCurrentOverload100PercentL1(0), ControlCurrentOverload110PercentL1(1), ControlCurrentOverload150PercentL1(2), ControlCurrentOverload200PercentL1(3), ControlCurrentOverload120PercentL1(4), ControlCurrentOverload300PercentL1(5), ControlTransientLoad300PercentL1(6), GridOverCurrentL1(7), LockingWaveformTooManyTimesL1(8), InverterVoltageZeroDriftErrorL1(9), GridVoltageZeroDriftErrorL1(10), ControlCurrentZeroDriftErrorL1(11), InverterCurrentZeroDriftErrorL1(12), GridCurrentZeroDriftErrorL1(13), PDPProtectionL1(14), HardwareControlCurrentProtectionL1(15), HardwareACVoltageProtectionL1(16), HardwareDCCurrentProtectionL1(17), HardwareTemperatureProtectionL1(18), NoCapturingSignalL1(19), DCOvervoltageL1(20), DCDisconnectedL1(21), InverterUndervoltageL1(22), InverterOvervoltageL1(23), CurrentSensorFailL1(24), VoltageSensorFailL1(25), PowerUncontrollableL1(26), CurrentUncontrollableL1(27), FanErrorL1(28), PhaseLackL1(29), InverterRelayFaultL1(30), GridRealyFaultL1(31), ControlPanelOvertempL1(32), PowerPanelOvertempL1(33), DCInputOvercurrentL1(34), CapacitorOvertempL1(35), RadiatorOvertempL1(36), TransformerOvertempL1(37), CombinationCommErrorL1(38), EEPROMErrorL1(39), LoadCurrentZeroDriftErrorL1(40), CurrentLimitRErrorL1(41), PhaseSyncErrorL1(42), ExternalPVCurrentZeroDriftErrorL1(43), ExternalGridCurrentZeroDriftErrorL1(44), + ControlCurrentOverload100PercentL2(45), ControlCurrentOverload110PercentL2(46), ControlCurrentOverload150PercentL2(47), ControlCurrentOverload200PercentL2(48), ControlCurrentOverload120PercentL2(49), ControlCurrentOverload300PercentL2(50), ControlTransientLoad300PercentL2(51), GridOverCurrentL2(52), LockingWaveformTooManyTimesL2(53), InverterVoltageZeroDriftErrorL2(54), GridVoltageZeroDriftErrorL2(55), ControlCurrentZeroDriftErrorL2(56), InverterCurrentZeroDriftErrorL2(57), GridCurrentZeroDriftErrorL2(58), PDPProtectionL2(59), HardwareControlCurrentProtectionL2(60), HardwareACVoltageProtectionL2(61), HardwareDCCurrentProtectionL2(62), HardwareTemperatureProtectionL2(63), NoCapturingSignalL2(64), DCOvervoltageL2(65), DCDisconnectedL2(66), InverterUndervoltageL2(67), InverterOvervoltageL2(68), CurrentSensorFailL2(69), VoltageSensorFailL2(70), PowerUncontrollableL2(71), CurrentUncontrollableL2(72), FanErrorL2(73), PhaseLackL2(74), InverterRelayFaultL2(75), GridRealyFaultL2(76), ControlPanelOvertempL2(77), PowerPanelOvertempL2(78), DCInputOvercurrentL2(79), CapacitorOvertempL2(80), RadiatorOvertempL2(81), TransformerOvertempL2(82), CombinationCommErrorL2(83), EEPROMErrorL2(84), LoadCurrentZeroDriftErrorL2(85), CurrentLimitRErrorL2(86), PhaseSyncErrorL2(87), ExternalPVCurrentZeroDriftErrorL2(88), ExternalGridCurrentZeroDriftErrorL2(89), + ControlCurrentOverload100PercentL3(90), ControlCurrentOverload110PercentL3(91), ControlCurrentOverload150PercentL3(92), ControlCurrentOverload200PercentL3(93), ControlCurrentOverload120PercentL3(94), ControlCurrentOverload300PercentL3(95), ControlTransientLoad300PercentL3(96), GridOverCurrentL3(97), LockingWaveformTooManyTimesL3(98), InverterVoltageZeroDriftErrorL3(99), GridVoltageZeroDriftErrorL3(100), ControlCurrentZeroDriftErrorL3(101), InverterCurrentZeroDriftErrorL3(102), GridCurrentZeroDriftErrorL3(103), PDPProtectionL3(104), HardwareControlCurrentProtectionL3(105), HardwareACVoltageProtectionL3(106), HardwareDCCurrentProtectionL3(107), HardwareTemperatureProtectionL3(108), NoCapturingSignalL3(109), DCOvervoltageL3(110), DCDisconnectedL3(111), InverterUndervoltageL3(112), InverterOvervoltageL3(113), CurrentSensorFailL3(114), VoltageSensorFailL3(115), PowerUncontrollableL3(116), CurrentUncontrollableL3(117), FanErrorL3(118), PhaseLackL3(119), InverterRelayFaultL3(120), GridRealyFaultL3(121), ControlPanelOvertempL3(122), PowerPanelOvertempL3(123), DCInputOvercurrentL3(124), CapacitorOvertempL3(125), RadiatorOvertempL3(126), TransformerOvertempL3(127), CombinationCommErrorL3(128), EEPROMErrorL3(129), LoadCurrentZeroDriftErrorL3(130), CurrentLimitRErrorL3(131), PhaseSyncErrorL3(132), ExternalPVCurrentZeroDriftErrorL3(133), ExternalGridCurrentZeroDriftErrorL3(134), + SystemFault(135), BatteryFault(136), PCSFault(137); + + private final int value; + + private FaultEss(int value) { + this.value = value; + } + + @Override + public int getValue() { + return this.value; + } +} diff --git a/edge/src/io/openems/impl/device/pro/FeneconPro.java b/edge/src/io/openems/impl/device/pro/FeneconPro.java index f09a77b32da..8b239fa2daa 100644 --- a/edge/src/io/openems/impl/device/pro/FeneconPro.java +++ b/edge/src/io/openems/impl/device/pro/FeneconPro.java @@ -45,10 +45,12 @@ public FeneconPro(Bridge parent) throws OpenemsException { * Config */ @ChannelInfo(title = "Ess", description = "Sets the Ess nature.", type = FeneconProEss.class) - public final ConfigChannel ess = new ConfigChannel<>("ess", this); + public final ConfigChannel ess = new ConfigChannel("ess", this) + .addChangeListener(this); @ChannelInfo(title = "Meter", description = "Sets the meter nature.", type = FeneconProPvMeter.class) - public final ConfigChannel meter = new ConfigChannel<>("meter", this); + public final ConfigChannel meter = new ConfigChannel("meter", this) + .addChangeListener(this); /* * Methods @@ -69,4 +71,5 @@ protected Set getDeviceNatures() { } return natures; } + } diff --git a/edge/src/io/openems/impl/device/pro/FeneconProEss.java b/edge/src/io/openems/impl/device/pro/FeneconProEss.java index 2770d34bf49..c43c7b82c39 100644 --- a/edge/src/io/openems/impl/device/pro/FeneconProEss.java +++ b/edge/src/io/openems/impl/device/pro/FeneconProEss.java @@ -24,9 +24,9 @@ import io.openems.api.channel.FunctionalReadChannel; import io.openems.api.channel.ReadChannel; import io.openems.api.channel.StaticValueChannel; -import io.openems.api.channel.StatusBitChannel; -import io.openems.api.channel.StatusBitChannels; +import io.openems.api.channel.ValueToBooleanThingStateChannel; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.ess.AsymmetricEssNature; import io.openems.api.device.nature.ess.EssNature; @@ -34,6 +34,7 @@ import io.openems.api.doc.ThingInfo; import io.openems.api.exception.ConfigException; import io.openems.api.exception.InvalidValueException; +import io.openems.impl.protocol.modbus.ModbusBitWrappingChannel; import io.openems.impl.protocol.modbus.ModbusDeviceNature; import io.openems.impl.protocol.modbus.ModbusReadLongChannel; import io.openems.impl.protocol.modbus.ModbusWriteLongChannel; @@ -67,6 +68,8 @@ public FeneconProEss(String thingId, Device parent) throws ConfigException { private ConfigChannel minSoc = new ConfigChannel("minSoc", this); private ConfigChannel chargeSoc = new ConfigChannel("chargeSoc", this); + private ThingStateChannels state = new ThingStateChannels(this); + @Override public ConfigChannel minSoc() { return minSoc; @@ -81,7 +84,6 @@ public ConfigChannel chargeSoc() { * Inherited Channels */ // ESS - private StatusBitChannels warning; private ModbusReadLongChannel allowedCharge; private ModbusReadLongChannel allowedDischarge; private ReadChannel gridMode; @@ -187,11 +189,6 @@ public WriteChannel setReactivePowerL3() { return setReactivePowerL3; } - @Override - public StatusBitChannels warning() { - return warning; - } - @Override public ReadChannel allowedApparent() { return allowedApparent; @@ -257,7 +254,6 @@ public WriteChannel rtcSecond() { public ModbusReadLongChannel voltageL3; public ModbusReadLongChannel pcsOperationState; public ModbusReadLongChannel batteryPower; - public ModbusReadLongChannel batteryGroupAlarm; public ModbusReadLongChannel batteryCurrent; public ModbusReadLongChannel batteryVoltage; public ModbusReadLongChannel batteryVoltageSection1; @@ -301,29 +297,12 @@ public WriteChannel rtcSecond() { public ModbusWriteLongChannel setSetupMode; public ModbusReadLongChannel setupMode; public ModbusReadLongChannel pcsMode; - public StatusBitChannel pcsAlarm1L1; - public StatusBitChannel pcsAlarm2L1; - public StatusBitChannel pcsFault1L1; - public StatusBitChannel pcsFault2L1; - public StatusBitChannel pcsFault3L1; - public StatusBitChannel pcsAlarm1L2; - public StatusBitChannel pcsAlarm2L2; - public StatusBitChannel pcsFault1L2; - public StatusBitChannel pcsFault2L2; - public StatusBitChannel pcsFault3L2; - public StatusBitChannel pcsAlarm1L3; - public StatusBitChannel pcsAlarm2L3; - public StatusBitChannel pcsFault1L3; - public StatusBitChannel pcsFault2L3; - public StatusBitChannel pcsFault3L3; /* * Methods */ @Override protected ModbusProtocol defineModbusProtocol() throws ConfigException { - warning = new StatusBitChannels("Warning", this); - ModbusProtocol protokol = new ModbusProtocol(new ModbusRegisterRange(100, // new UnsignedWordElement(100, // systemState = new ModbusReadLongChannel("SystemState", this) // @@ -364,15 +343,14 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { batteryCurrent = new ModbusReadLongChannel("BatteryCurrent", this).unit("mA").multiplier(2)), new SignedWordElement(112, // batteryPower = new ModbusReadLongChannel("BatteryPower", this).unit("W")), - new UnsignedWordElement(113, // - batteryGroupAlarm = new ModbusReadLongChannel("BatteryGroupAlarm", this) - .label(1, "Fail, The system should be stopped") // - .label(2, "Common low voltage alarm") // - .label(4, "Common high voltage alarm") // - .label(8, "Charging over current alarm") // - .label(16, "Discharging over current alarm") // - .label(32, "Over temperature alarm")// - .label(64, "Interal communication abnormal")), + new UnsignedWordElement(113, new ModbusBitWrappingChannel("BatteryGroupAlarm", this, state)// + .warningBit(0, WarningEss.FailTheSystemShouldBeStopped) // Fail, The system should be stopped + .warningBit(1, WarningEss.CommonLowVoltageAlarm) // Common low voltage alarm + .warningBit(2, WarningEss.CommonHighVoltageAlarm) // Common high voltage alarm + .warningBit(3, WarningEss.ChargingOverCurrentAlarm) // Charging over current alarm + .warningBit(4, WarningEss.DischargingOverCurrentAlarm) // Discharging over current alarm + .warningBit(5, WarningEss.OverTemperatureAlarm) // Over temperature alarm + .warningBit(6, WarningEss.InteralCommunicationAbnormal)), // Interal communication abnormal new UnsignedWordElement(114, // pcsOperationState = new ModbusReadLongChannel("PcsOperationState", this) .label(0, "Self-checking") // @@ -421,223 +399,196 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { new UnsignedWordElement(142, // allowedDischarge = new ModbusReadLongChannel("AllowedDischarge", this).unit("W"))), new ModbusRegisterRange(150, - new UnsignedWordElement(150, - pcsAlarm1L1 = warning.channel(new StatusBitChannel("PcsAlarm1L1", this)// - .label(1, "Grid undervoltage") // - .label(2, "Grid overvoltage") // - .label(4, "Grid under frequency") // - .label(8, "Grid over frequency") // - .label(16, "Grid power supply off") // - .label(32, "Grid condition unmeet")// - .label(64, "DC under voltage")// - .label(128, "Input over resistance")// - .label(256, "Combination error")// - .label(512, "Comm with inverter error")// - .label(1024, "Tme error")// - )), new UnsignedWordElement(151, - pcsAlarm2L1 = warning.channel(new StatusBitChannel("PcsAlarm2L1", this)// - )), - new UnsignedWordElement(152, - warning.channel(pcsFault1L1 = new StatusBitChannel("PcsFault1L1", this)// - .label(1, "Control current overload 100%")// - .label(2, "Control current overload 110%")// - .label(4, "Control current overload 150%")// - .label(8, "Control current overload 200%")// - .label(16, "Control current overload 120%")// - .label(32, "Control current overload 300%")// - .label(64, "Control transient load 300%")// - .label(128, "Grid over current")// - .label(256, "Locking waveform too many times")// - .label(512, "Inverter voltage zero drift error")// - .label(1024, "Grid voltage zero drift error")// - .label(2048, "Control current zero drift error")// - .label(4096, "Inverter current zero drift error")// - .label(8192, "Grid current zero drift error")// - .label(16384, "PDP protection")// - .label(32768, "Hardware control current protection")// - )), - new UnsignedWordElement(153, - warning.channel(pcsFault2L1 = new StatusBitChannel("PcsFault2L1", this)// - .label(1, "Hardware AC volt. protection")// - .label(2, "Hardware DC curr. protection")// - .label(4, "Hardware temperature protection")// - .label(8, "No capturing signal")// - .label(16, "DC overvoltage")// - .label(32, "DC disconnected")// - .label(64, "Inverter undervoltage")// - .label(128, "Inverter overvoltage")// - .label(256, "Current sensor fail")// - .label(512, "Voltage sensor fail")// - .label(1024, "Power uncontrollable")// - .label(2048, "Current uncontrollable")// - .label(4096, "Fan error")// - .label(8192, "Phase lack")// - .label(16384, "Inverter relay fault")// - .label(32768, "Grid relay fault")// - )), - new UnsignedWordElement(154, - warning.channel(pcsFault3L1 = new StatusBitChannel("PcsFault3L1", this)// - .label(1, "Control panel overtemp")// - .label(2, "Power panel overtemp")// - .label(4, "DC input overcurrent")// - .label(8, "Capacitor overtemp")// - .label(16, "Radiator overtemp")// - .label(32, "Transformer overtemp")// - .label(64, "Combination comm error")// - .label(128, "EEPROM error")// - .label(256, "Load current zero drift error")// - .label(512, "Current limit-R error")// - .label(1024, "Phase sync error")// - .label(2048, "External PV current zero drift error")// - .label(4096, "External grid current zero drift error")// - )), - new UnsignedWordElement(155, - warning.channel(pcsAlarm1L2 = new StatusBitChannel("PcsAlarm1L2", this)// - .label(1, "Grid undervoltage") // - .label(2, "Grid overvoltage") // - .label(4, "Grid under frequency") // - .label(8, "Grid over frequency") // - .label(16, "Grid power supply off") // - .label(32, "Grid condition unmeet")// - .label(64, "DC under voltage")// - .label(128, "Input over resistance")// - .label(256, "Combination error")// - .label(512, "Comm with inverter error")// - .label(1024, "Tme error")// - )), new UnsignedWordElement(156, - warning.channel(pcsAlarm2L2 = new StatusBitChannel("PcsAlarm2L2", this)// - )), - new UnsignedWordElement(157, - warning.channel(pcsFault1L2 = new StatusBitChannel("PcsFault1L2", this)// - .label(1, "Control current overload 100%")// - .label(2, "Control current overload 110%")// - .label(4, "Control current overload 150%")// - .label(8, "Control current overload 200%")// - .label(16, "Control current overload 120%")// - .label(32, "Control current overload 300%")// - .label(64, "Control transient load 300%")// - .label(128, "Grid over current")// - .label(256, "Locking waveform too many times")// - .label(512, "Inverter voltage zero drift error")// - .label(1024, "Grid voltage zero drift error")// - .label(2048, "Control current zero drift error")// - .label(4096, "Inverter current zero drift error")// - .label(8192, "Grid current zero drift error")// - .label(16384, "PDP protection")// - .label(32768, "Hardware control current protection")// - )), - new UnsignedWordElement(158, - warning.channel(pcsFault2L2 = new StatusBitChannel("PcsFault2L2", this)// - .label(1, "Hardware AC volt. protection")// - .label(2, "Hardware DC curr. protection")// - .label(4, "Hardware temperature protection")// - .label(8, "No capturing signal")// - .label(16, "DC overvoltage")// - .label(32, "DC disconnected")// - .label(64, "Inverter undervoltage")// - .label(128, "Inverter overvoltage")// - .label(256, "Current sensor fail")// - .label(512, "Voltage sensor fail")// - .label(1024, "Power uncontrollable")// - .label(2048, "Current uncontrollable")// - .label(4096, "Fan error")// - .label(8192, "Phase lack")// - .label(16384, "Inverter relay fault")// - .label(32768, "Grid relay fault")// - )), - new UnsignedWordElement(159, - warning.channel(pcsFault3L2 = new StatusBitChannel("PcsFault3L2", this)// - .label(1, "Control panel overtemp")// - .label(2, "Power panel overtemp")// - .label(4, "DC input overcurrent")// - .label(8, "Capacitor overtemp")// - .label(16, "Radiator overtemp")// - .label(32, "Transformer overtemp")// - .label(64, "Combination comm error")// - .label(128, "EEPROM error")// - .label(256, "Load current zero drift error")// - .label(512, "Current limit-R error")// - .label(1024, "Phase sync error")// - .label(2048, "External PV current zero drift error")// - .label(4096, "External grid current zero drift error")// - )), - new UnsignedWordElement(160, - warning.channel(pcsAlarm1L3 = new StatusBitChannel("PcsAlarm1L3", this)// - .label(1, "Grid undervoltage") // - .label(2, "Grid overvoltage") // - .label(4, "Grid under frequency") // - .label(8, "Grid over frequency") // - .label(16, "Grid power supply off") // - .label(32, "Grid condition unmeet")// - .label(64, "DC under voltage")// - .label(128, "Input over resistance")// - .label(256, "Combination error")// - .label(512, "Comm with inverter error")// - .label(1024, "Tme error")// - )), new UnsignedWordElement(161, - warning.channel(pcsAlarm2L3 = new StatusBitChannel("PcsAlarm2L3", this)// - )), - new UnsignedWordElement(162, - warning.channel(pcsFault1L3 = new StatusBitChannel("PcsFault1L3", this)// - .label(1, "Control current overload 100%")// - .label(2, "Control current overload 110%")// - .label(4, "Control current overload 150%")// - .label(8, "Control current overload 200%")// - .label(16, "Control current overload 120%")// - .label(32, "Control current overload 300%")// - .label(64, "Control transient load 300%")// - .label(128, "Grid over current")// - .label(256, "Locking waveform too many times")// - .label(512, "Inverter voltage zero drift error")// - .label(1024, "Grid voltage zero drift error")// - .label(2048, "Control current zero drift error")// - .label(4096, "Inverter current zero drift error")// - .label(8192, "Grid current zero drift error")// - .label(16384, "PDP protection")// - .label(32768, "Hardware control current protection")// - )), - new UnsignedWordElement(163, - warning.channel(pcsFault2L3 = new StatusBitChannel("PcsFault2L3", this)// - .label(1, "Hardware AC volt. protection")// - .label(2, "Hardware DC curr. protection")// - .label(4, "Hardware temperature protection")// - .label(8, "No capturing signal")// - .label(16, "DC overvoltage")// - .label(32, "DC disconnected")// - .label(64, "Inverter undervoltage")// - .label(128, "Inverter overvoltage")// - .label(256, "Current sensor fail")// - .label(512, "Voltage sensor fail")// - .label(1024, "Power uncontrollable")// - .label(2048, "Current uncontrollable")// - .label(4096, "Fan error")// - .label(8192, "Phase lack")// - .label(16384, "Inverter relay fault")// - .label(32768, "Grid relay fault")// - )), - new UnsignedWordElement(164, - warning.channel(pcsFault3L3 = new StatusBitChannel("PcsFault3L3", this)// - .label(1, "Control panel overtemp")// - .label(2, "Power panel overtemp")// - .label(4, "DC input overcurrent")// - .label(8, "Capacitor overtemp")// - .label(16, "Radiator overtemp")// - .label(32, "Transformer overtemp")// - .label(64, "Combination comm error")// - .label(128, "EEPROM error")// - .label(256, "Load current zero drift error")// - .label(512, "Current limit-R error")// - .label(1024, "Phase sync error")// - .label(2048, "External PV current zero drift error")// - .label(4096, "External grid current zero drift error")// - ))), // + new UnsignedWordElement(150, new ModbusBitWrappingChannel("PcsAlarm1L1", this, state)// + .warningBit(0, WarningEss.GridUndervoltageL1) // Grid undervoltage + .warningBit(1, WarningEss.GridOvervoltageL1) // Grid overvoltage + .warningBit(2, WarningEss.GridUnderFrequencyL1) // Grid under frequency + .warningBit(3, WarningEss.GridOverFrequencyL1) // Grid over frequency + .warningBit(4, WarningEss.GridPowerSupplyOffL1) // Grid power supply off + .warningBit(5, WarningEss.GridConditionUnmeetL1) // Grid condition unmeet + .warningBit(6, WarningEss.DCUnderVoltageL1) // DC under voltage + .warningBit(7, WarningEss.InputOverResistanceL1) // Input over resistance + .warningBit(8, WarningEss.CombinationErrorL1) // Combination error + .warningBit(9, WarningEss.CommWithInverterErrorL1) // Comm with inverter error + .warningBit(10, WarningEss.TmeErrorL1)), // Tme error + new UnsignedWordElement(151, new ModbusBitWrappingChannel("PcsAlarm2L1", this, state)), + new UnsignedWordElement(152, new ModbusBitWrappingChannel("PcsFault1L1", this, state)// + .faultBit(0, FaultEss.ControlCurrentOverload100PercentL1) // Control current overload 100% + .faultBit(1, FaultEss.ControlCurrentOverload110PercentL1) // Control current overload 110% + .faultBit(2, FaultEss.ControlCurrentOverload150PercentL1) // Control current overload 150% + .faultBit(3, FaultEss.ControlCurrentOverload200PercentL1) // Control current overload 200% + .faultBit(4, FaultEss.ControlCurrentOverload120PercentL1) // Control current overload 120% + .faultBit(5, FaultEss.ControlCurrentOverload300PercentL1) // Control current overload 300% + .faultBit(6, FaultEss.ControlTransientLoad300PercentL1) // Control transient load 300% + .faultBit(7, FaultEss.GridOverCurrentL1) // Grid over current + .faultBit(8, FaultEss.LockingWaveformTooManyTimesL1) // Locking waveform too many times + .faultBit(9, FaultEss.InverterVoltageZeroDriftErrorL1) // Inverter voltage zero drift error + .faultBit(10, FaultEss.GridVoltageZeroDriftErrorL1) // Grid voltage zero drift error + .faultBit(11, FaultEss.ControlCurrentZeroDriftErrorL1) // Control current zero drift error + .faultBit(12, FaultEss.InverterCurrentZeroDriftErrorL1) // Inverter current zero drift error + .faultBit(13, FaultEss.GridCurrentZeroDriftErrorL1) // Grid current zero drift error + .faultBit(14, FaultEss.PDPProtectionL1) // PDP protection + .faultBit(15, FaultEss.HardwareControlCurrentProtectionL1)), // Hardware control current protection + new UnsignedWordElement(153, new ModbusBitWrappingChannel("PcsFault2L1", this, state)// + .faultBit(0, FaultEss.HardwareACVoltageProtectionL1) // Hardware AC volt. protection + .faultBit(1, FaultEss.HardwareDCCurrentProtectionL1) // Hardware DC curr. protection + .faultBit(2, FaultEss.HardwareTemperatureProtectionL1) // Hardware temperature protection + .faultBit(3, FaultEss.NoCapturingSignalL1) // No capturing signal + .faultBit(4, FaultEss.DCOvervoltageL1) // DC overvoltage + .faultBit(5, FaultEss.DCDisconnectedL1) // DC disconnected + .faultBit(6, FaultEss.InverterUndervoltageL1) // Inverter undervoltage + .faultBit(7, FaultEss.InverterOvervoltageL1) // Inverter overvoltage + .faultBit(8, FaultEss.CurrentSensorFailL1) // Current sensor fail + .faultBit(9, FaultEss.VoltageSensorFailL1) // Voltage sensor fail + .faultBit(10, FaultEss.PowerUncontrollableL1) // Power uncontrollable + .faultBit(11, FaultEss.CurrentUncontrollableL1) // Current uncontrollable + .faultBit(12, FaultEss.FanErrorL1) // Fan error + .faultBit(13, FaultEss.PhaseLackL1) // Phase lack + .faultBit(14, FaultEss.InverterRelayFaultL1) // Inverter relay fault + .faultBit(15, FaultEss.GridRealyFaultL1)), // Grid relay fault + new UnsignedWordElement(154, new ModbusBitWrappingChannel("PcsFault3L1", this, state)// + .faultBit(0, FaultEss.ControlPanelOvertempL1) // Control panel overtemp + .faultBit(1, FaultEss.PowerPanelOvertempL1) // Power panel overtemp + .faultBit(2, FaultEss.DCInputOvercurrentL1) // DC input overcurrent + .faultBit(3, FaultEss.CapacitorOvertempL1) // Capacitor overtemp + .faultBit(4, FaultEss.RadiatorOvertempL1) // Radiator overtemp + .faultBit(5, FaultEss.TransformerOvertempL1) // Transformer overtemp + .faultBit(6, FaultEss.CombinationCommErrorL1) // Combination comm error + .faultBit(7, FaultEss.EEPROMErrorL1) // EEPROM error + .faultBit(8, FaultEss.LoadCurrentZeroDriftErrorL1) // Load current zero drift error + .faultBit(9, FaultEss.CurrentLimitRErrorL1) // Current limit-R error + .faultBit(10, FaultEss.PhaseSyncErrorL1) // Phase sync error + .faultBit(11, FaultEss.ExternalPVCurrentZeroDriftErrorL1) // External PV current zero drift error + .faultBit(12, FaultEss.ExternalGridCurrentZeroDriftErrorL1)), // External grid current zero drift error + new UnsignedWordElement(155, new ModbusBitWrappingChannel("PcsAlarm1L2", this, state)// + .warningBit(0, WarningEss.GridUndervoltageL2) // Grid undervoltage + .warningBit(1, WarningEss.GridOvervoltageL2) // Grid overvoltage + .warningBit(2, WarningEss.GridUnderFrequencyL2) // Grid under frequency + .warningBit(3, WarningEss.GridOverFrequencyL2) // Grid over frequency + .warningBit(4, WarningEss.GridPowerSupplyOffL2) // Grid power supply off + .warningBit(5, WarningEss.GridConditionUnmeetL2) // Grid condition unmeet + .warningBit(6, WarningEss.DCUnderVoltageL2) // DC under voltage + .warningBit(7, WarningEss.InputOverResistanceL2) // Input over resistance + .warningBit(8, WarningEss.CombinationErrorL2) // Combination error + .warningBit(9, WarningEss.CommWithInverterErrorL2) // Comm with inverter error + .warningBit(10, WarningEss.TmeErrorL2)), // Tme error + new UnsignedWordElement(156, new ModbusBitWrappingChannel("PcsAlarm2L2", this, state)), + new UnsignedWordElement(157, new ModbusBitWrappingChannel("PcsFault1L2", this, state)// + .faultBit(0, FaultEss.ControlCurrentOverload100PercentL2) // Control current overload 100% + .faultBit(1, FaultEss.ControlCurrentOverload110PercentL2) // Control current overload 110% + .faultBit(2, FaultEss.ControlCurrentOverload150PercentL2) // Control current overload 150% + .faultBit(3, FaultEss.ControlCurrentOverload200PercentL2) // Control current overload 200% + .faultBit(4, FaultEss.ControlCurrentOverload120PercentL2) // Control current overload 120% + .faultBit(5, FaultEss.ControlCurrentOverload300PercentL2) // Control current overload 300% + .faultBit(6, FaultEss.ControlTransientLoad300PercentL2) // Control transient load 300% + .faultBit(7, FaultEss.GridOverCurrentL2) // Grid over current + .faultBit(8, FaultEss.LockingWaveformTooManyTimesL2) // Locking waveform too many times + .faultBit(9, FaultEss.InverterVoltageZeroDriftErrorL2) // Inverter voltage zero drift error + .faultBit(10, FaultEss.GridVoltageZeroDriftErrorL2) // Grid voltage zero drift error + .faultBit(11, FaultEss.ControlCurrentZeroDriftErrorL2) // Control current zero drift error + .faultBit(12, FaultEss.InverterCurrentZeroDriftErrorL2) // Inverter current zero drift error + .faultBit(13, FaultEss.GridCurrentZeroDriftErrorL2) // Grid current zero drift error + .faultBit(14, FaultEss.PDPProtectionL2) // PDP protection + .faultBit(15, FaultEss.HardwareControlCurrentProtectionL2)), // Hardware control current protection + new UnsignedWordElement(158, new ModbusBitWrappingChannel("PcsFault2L2", this, state)// + .faultBit(0, FaultEss.HardwareACVoltageProtectionL2) // Hardware AC volt. protection + .faultBit(1, FaultEss.HardwareDCCurrentProtectionL2) // Hardware DC curr. protection + .faultBit(2, FaultEss.HardwareTemperatureProtectionL2) // Hardware temperature protection + .faultBit(3, FaultEss.NoCapturingSignalL2) // No capturing signal + .faultBit(4, FaultEss.DCOvervoltageL2) // DC overvoltage + .faultBit(5, FaultEss.DCDisconnectedL2) // DC disconnected + .faultBit(6, FaultEss.InverterUndervoltageL2) // Inverter undervoltage + .faultBit(7, FaultEss.InverterOvervoltageL2) // Inverter overvoltage + .faultBit(8, FaultEss.CurrentSensorFailL2) // Current sensor fail + .faultBit(9, FaultEss.VoltageSensorFailL2) // Voltage sensor fail + .faultBit(10, FaultEss.PowerUncontrollableL2) // Power uncontrollable + .faultBit(11, FaultEss.CurrentUncontrollableL2) // Current uncontrollable + .faultBit(12, FaultEss.FanErrorL2) // Fan error + .faultBit(13, FaultEss.PhaseLackL2) // Phase lack + .faultBit(14, FaultEss.InverterRelayFaultL2) // Inverter relay fault + .faultBit(15, FaultEss.GridRealyFaultL2)), // Grid relay fault + new UnsignedWordElement(159, new ModbusBitWrappingChannel("PcsFault3L2", this, state)// + .faultBit(0, FaultEss.ControlPanelOvertempL2) // Control panel overtemp + .faultBit(1, FaultEss.PowerPanelOvertempL2) // Power panel overtemp + .faultBit(2, FaultEss.DCInputOvercurrentL2) // DC input overcurrent + .faultBit(3, FaultEss.CapacitorOvertempL2) // Capacitor overtemp + .faultBit(4, FaultEss.RadiatorOvertempL2) // Radiator overtemp + .faultBit(5, FaultEss.TransformerOvertempL2) // Transformer overtemp + .faultBit(6, FaultEss.CombinationCommErrorL2) // Combination comm error + .faultBit(7, FaultEss.EEPROMErrorL2) // EEPROM error + .faultBit(8, FaultEss.LoadCurrentZeroDriftErrorL2) // Load current zero drift error + .faultBit(9, FaultEss.CurrentLimitRErrorL2) // Current limit-R error + .faultBit(10, FaultEss.PhaseSyncErrorL2) // Phase sync error + .faultBit(11, FaultEss.ExternalPVCurrentZeroDriftErrorL2) // External PV current zero drift error + .faultBit(12, FaultEss.ExternalGridCurrentZeroDriftErrorL2)), // External grid current zero drift error + new UnsignedWordElement(160, new ModbusBitWrappingChannel("PcsAlarm1L3", this, state)// + .warningBit(0, WarningEss.GridUndervoltageL3) // Grid undervoltage + .warningBit(1, WarningEss.GridOvervoltageL3) // Grid overvoltage + .warningBit(2, WarningEss.GridUnderFrequencyL3) // Grid under frequency + .warningBit(3, WarningEss.GridOverFrequencyL3) // Grid over frequency + .warningBit(4, WarningEss.GridPowerSupplyOffL3) // Grid power supply off + .warningBit(5, WarningEss.GridConditionUnmeetL3) // Grid condition unmeet + .warningBit(6, WarningEss.DCUnderVoltageL3) // DC under voltage + .warningBit(7, WarningEss.InputOverResistanceL3) // Input over resistance + .warningBit(8, WarningEss.CombinationErrorL3) // Combination error + .warningBit(9, WarningEss.CommWithInverterErrorL3) // Comm with inverter error + .warningBit(10, WarningEss.TmeErrorL3)), // Tme error + new UnsignedWordElement(161, new ModbusBitWrappingChannel("PcsAlarm2L3", this, state)), + new UnsignedWordElement(162, new ModbusBitWrappingChannel("PcsFault1L3", this, state)// + .faultBit(0, FaultEss.ControlCurrentOverload100PercentL3) // Control current overload 100% + .faultBit(1, FaultEss.ControlCurrentOverload110PercentL3) // Control current overload 110% + .faultBit(2, FaultEss.ControlCurrentOverload150PercentL3) // Control current overload 150% + .faultBit(3, FaultEss.ControlCurrentOverload200PercentL3) // Control current overload 200% + .faultBit(4, FaultEss.ControlCurrentOverload120PercentL3) // Control current overload 120% + .faultBit(5, FaultEss.ControlCurrentOverload300PercentL3) // Control current overload 300% + .faultBit(6, FaultEss.ControlTransientLoad300PercentL3) // Control transient load 300% + .faultBit(7, FaultEss.GridOverCurrentL3) // Grid over current + .faultBit(8, FaultEss.LockingWaveformTooManyTimesL3) // Locking waveform too many times + .faultBit(9, FaultEss.InverterVoltageZeroDriftErrorL3) // Inverter voltage zero drift error + .faultBit(10, FaultEss.GridVoltageZeroDriftErrorL3) // Grid voltage zero drift error + .faultBit(11, FaultEss.ControlCurrentZeroDriftErrorL3) // Control current zero drift error + .faultBit(12, FaultEss.InverterCurrentZeroDriftErrorL3) // Inverter current zero drift error + .faultBit(13, FaultEss.GridCurrentZeroDriftErrorL3) // Grid current zero drift error + .faultBit(14, FaultEss.PDPProtectionL3) // PDP protection + .faultBit(15, FaultEss.HardwareControlCurrentProtectionL3)), // Hardware control current protection + new UnsignedWordElement(163, new ModbusBitWrappingChannel("PcsFault2L3", this, state)// + .faultBit(0, FaultEss.HardwareACVoltageProtectionL3) // Hardware AC volt. protection + .faultBit(1, FaultEss.HardwareDCCurrentProtectionL3) // Hardware DC curr. protection + .faultBit(2, FaultEss.HardwareTemperatureProtectionL3) // Hardware temperature protection + .faultBit(3, FaultEss.NoCapturingSignalL3) // No capturing signal + .faultBit(4, FaultEss.DCOvervoltageL3) // DC overvoltage + .faultBit(5, FaultEss.DCDisconnectedL3) // DC disconnected + .faultBit(6, FaultEss.InverterUndervoltageL3) // Inverter undervoltage + .faultBit(7, FaultEss.InverterOvervoltageL3) // Inverter overvoltage + .faultBit(8, FaultEss.CurrentSensorFailL3) // Current sensor fail + .faultBit(9, FaultEss.VoltageSensorFailL3) // Voltage sensor fail + .faultBit(10, FaultEss.PowerUncontrollableL3) // Power uncontrollable + .faultBit(11, FaultEss.CurrentUncontrollableL3) // Current uncontrollable + .faultBit(12, FaultEss.FanErrorL3) // Fan error + .faultBit(13, FaultEss.PhaseLackL3) // Phase lack + .faultBit(14, FaultEss.InverterRelayFaultL3) // Inverter relay fault + .faultBit(15, FaultEss.GridRealyFaultL3)), // Grid relay fault + new UnsignedWordElement(164, new ModbusBitWrappingChannel("PcsFault3L3", this, state)// + .faultBit(0, FaultEss.ControlPanelOvertempL3) // Control panel overtemp + .faultBit(1, FaultEss.PowerPanelOvertempL3) // Power panel overtemp + .faultBit(2, FaultEss.DCInputOvercurrentL3) // DC input overcurrent + .faultBit(3, FaultEss.CapacitorOvertempL3) // Capacitor overtemp + .faultBit(4, FaultEss.RadiatorOvertempL3) // Radiator overtemp + .faultBit(5, FaultEss.TransformerOvertempL3) // Transformer overtemp + .faultBit(6, FaultEss.CombinationCommErrorL3) // Combination comm error + .faultBit(7, FaultEss.EEPROMErrorL3) // EEPROM error + .faultBit(8, FaultEss.LoadCurrentZeroDriftErrorL3) // Load current zero drift error + .faultBit(9, FaultEss.CurrentLimitRErrorL3) // Current limit-R error + .faultBit(10, FaultEss.PhaseSyncErrorL3) // Phase sync error + .faultBit(11, FaultEss.ExternalPVCurrentZeroDriftErrorL3) // External PV current zero drift error + .faultBit(12, FaultEss.ExternalGridCurrentZeroDriftErrorL3))), // External grid current zero drift error new WriteableModbusRegisterRange(200, // new UnsignedWordElement(200, setWorkState = new ModbusWriteLongChannel("SetWorkState", this)// .label(0, "Local control") // .label(1, START) // "Remote control on grid starting" .label(2, "Remote control off grid starting") // - .label(3, STOP)// - .label(4, "Emergency Stop"))), + .label(3, STANDBY)// + .label(4, STOP))), new WriteableModbusRegisterRange(206, // new SignedWordElement(206, setActivePowerL1 = new ModbusWriteLongChannel("SetActivePowerL1", this).unit("W")), // @@ -804,6 +755,13 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { return 0l; }, phaseAllowedApparent); + // FaultChannels + state.addFaultChannel(new ValueToBooleanThingStateChannel(FaultEss.SystemFault, this, systemState, 3L)); + state.addFaultChannel(new ValueToBooleanThingStateChannel(FaultEss.BatteryFault, this, batteryGroupState, 5L)); + state.addFaultChannel(new ValueToBooleanThingStateChannel(FaultEss.PCSFault, this, pcsOperationState, 5L)); + // WarningChannels + state.addWarningChannel(new ValueToBooleanThingStateChannel(WarningEss.OFFGrid, this, systemState, 1L)); + return protokol; } @@ -817,4 +775,9 @@ public ReadChannel maxNominalPower() { return maxNominalPower; } + @Override + public ThingStateChannels getStateChannel() { + return state; + } + } diff --git a/edge/src/io/openems/impl/device/pro/FeneconProPvMeter.java b/edge/src/io/openems/impl/device/pro/FeneconProPvMeter.java index 8a23afe0c03..db2abfed4c0 100644 --- a/edge/src/io/openems/impl/device/pro/FeneconProPvMeter.java +++ b/edge/src/io/openems/impl/device/pro/FeneconProPvMeter.java @@ -23,6 +23,8 @@ import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.FunctionalReadChannel; import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.StaticThingStateChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.meter.AsymmetricMeterNature; import io.openems.api.device.nature.meter.SymmetricMeterNature; @@ -46,6 +48,13 @@ public class FeneconProPvMeter extends ModbusDeviceNature implements AsymmetricM */ public FeneconProPvMeter(String thingId, Device parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); + this.negativePowerL1 = new StaticThingStateChannel(WarningPvMeter.NegativePowerL1, this, false); + this.thingState.addWarningChannel(this.negativePowerL1); + this.negativePowerL2 = new StaticThingStateChannel(WarningPvMeter.NegativePowerL2, this, false); + this.thingState.addWarningChannel(this.negativePowerL2); + this.negativePowerL3 = new StaticThingStateChannel(WarningPvMeter.NegativePowerL3, this, false); + this.thingState.addWarningChannel(this.negativePowerL3); } /* @@ -94,6 +103,10 @@ public ConfigChannel minActivePower() { private ModbusReadChannel orginalActivePowerL1; private ModbusReadChannel orginalActivePowerL2; private ModbusReadChannel orginalActivePowerL3; + private ThingStateChannels thingState; + private StaticThingStateChannel negativePowerL1; + private StaticThingStateChannel negativePowerL2; + private StaticThingStateChannel negativePowerL3; @Override public ReadChannel activePowerL1() { @@ -199,30 +212,32 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { new ModbusRegisterRange(2035, // new UnsignedDoublewordElement(2035, // activeEnergyL1 = new ModbusReadLongChannel("ActiveEnergyL1", this) - .unit("Wh").multiplier(2)), + .unit("Wh").multiplier(2)), new DummyElement(2037, 2065), new UnsignedWordElement(2066, // orginalActivePowerL1 = new ModbusReadLongChannel("OriginalActivePowerL1", this) - .unit("W").delta(10000L))), + .unit("W").delta(10000L))), new ModbusRegisterRange(2135, // new UnsignedDoublewordElement(2135, // activeEnergyL2 = new ModbusReadLongChannel("ActiveEnergyL2", this) - .unit("Wh").multiplier(2)), + .unit("Wh").multiplier(2)), new DummyElement(2137, 2165), new UnsignedWordElement(2166, // orginalActivePowerL2 = new ModbusReadLongChannel("OriginalActivePowerL2", this) - .unit("W").delta(10000L))), + .unit("W").delta(10000L))), new ModbusRegisterRange(2235, // new UnsignedDoublewordElement(2235, // activeEnergyL3 = new ModbusReadLongChannel("ActiveEnergyL3", this) - .unit("Wh").multiplier(2)), + .unit("Wh").multiplier(2)), new DummyElement(2237, 2265), new UnsignedWordElement(2266, // orginalActivePowerL3 = new ModbusReadLongChannel("OriginalActivePowerL3", this) - .unit("W").delta(10000L)))); + .unit("W").delta(10000L)))); activePowerL1 = new FunctionalReadChannel("ActivePowerL1", this, (channels) -> { ReadChannel power = channels[0]; try { if (power.value() >= 0) { + this.negativePowerL1.setValue(false); return power.value(); } else { + this.negativePowerL1.setValue(true); return 0L; } } catch (InvalidValueException e) { @@ -233,8 +248,10 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { ReadChannel power = channels[0]; try { if (power.value() >= 0) { + this.negativePowerL2.setValue(false); return power.value(); } else { + this.negativePowerL2.setValue(true); return 0L; } } catch (InvalidValueException e) { @@ -245,8 +262,10 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { ReadChannel power = channels[0]; try { if (power.value() >= 0) { + this.negativePowerL3.setValue(false); return power.value(); } else { + this.negativePowerL3.setValue(true); return 0L; } } catch (InvalidValueException e) { @@ -275,4 +294,9 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { }, reactivePowerL1, reactivePowerL2, reactivePowerL3); return protocol; } + + @Override + public ThingStateChannels getStateChannel() { + return thingState; + } } diff --git a/edge/src/io/openems/impl/device/pro/Readme.md b/edge/src/io/openems/impl/device/pro/Readme.md index 3eae66dc7d8..5bcb49882f6 100644 --- a/edge/src/io/openems/impl/device/pro/Readme.md +++ b/edge/src/io/openems/impl/device/pro/Readme.md @@ -1,3 +1,112 @@ +# FENECON Pro ESS + + +Following Values are implemented: + +|ChannelName|Unit| +|---|---| +|ActivePowerL1|W| +|ActivePowerL2|W| +|ActivePowerL3|W| +|alias|| +|AllowedApparent|| +|AllowedCharge|W| +|AllowedDischarge|W| +|BatteryCurrent|mA| +|BatteryGroupAlarm|1: Fail, The system should be stopped
2: Common low voltage alarm
4: Common high voltage alarm
8: Charging over current alarm
16: Discharging over current alarm
32: Over temperature alarm
64: Interal communication abnormal
| +|BatteryGroupState|0: Initial
1: Stop
2: Starting
3: Running
4: Stopping
5: Fail
| +|BatteryPower|W| +|BatteryTemperatureSection1|°C| +|BatteryTemperatureSection10|°C| +|BatteryTemperatureSection11|°C| +|BatteryTemperatureSection12|°C| +|BatteryTemperatureSection13|°C| +|BatteryTemperatureSection14|°C| +|BatteryTemperatureSection15|°C| +|BatteryTemperatureSection16|°C| +|BatteryTemperatureSection2|°C| +|BatteryTemperatureSection3|°C| +|BatteryTemperatureSection4|°C| +|BatteryTemperatureSection5|°C| +|BatteryTemperatureSection6|°C| +|BatteryTemperatureSection7|°C| +|BatteryTemperatureSection8|°C| +|BatteryTemperatureSection9|°C| +|BatteryVoltage|mV| +|BatteryVoltageSection1|mV| +|BatteryVoltageSection10|mV| +|BatteryVoltageSection11|mV| +|BatteryVoltageSection12|mV| +|BatteryVoltageSection13|mV| +|BatteryVoltageSection14|mV| +|BatteryVoltageSection15|mV| +|BatteryVoltageSection16|mV| +|BatteryVoltageSection2|mV| +|BatteryVoltageSection3|mV| +|BatteryVoltageSection4|mV| +|BatteryVoltageSection5|mV| +|BatteryVoltageSection6|mV| +|BatteryVoltageSection7|mV| +|BatteryVoltageSection8|mV| +|BatteryVoltageSection9|mV| +|capacity|Wh| +|chargeSoc|| +|ControlMode|1: Remote
2: Local
| +|CurrentL1|mA| +|CurrentL2|mA| +|CurrentL3|mA| +|FrequencyL1|mHz| +|FrequencyL2|mHz| +|FrequencyL3|mHz| +|GridMode|0: Off-Grid
1: On-Grid
| +|maxNominalPower|VA| +|minSoc|| +|PcsAlarm1L1|1: Grid undervoltage
2: Grid overvoltage
4: Grid under frequency
8: Grid over frequency
16: Grid power supply off
32: Grid condition unmeet
64: DC under voltage
128: Input over resistance
256: Combination error
512: Comm with inverter error
1024: Tme error
| +|PcsAlarm1L2|1: Grid undervoltage
2: Grid overvoltage
4: Grid under frequency
8: Grid over frequency
16: Grid power supply off
32: Grid condition unmeet
64: DC under voltage
128: Input over resistance
256: Combination error
512: Comm with inverter error
1024: Tme error
| +|PcsAlarm1L3|1: Grid undervoltage
2: Grid overvoltage
4: Grid under frequency
8: Grid over frequency
16: Grid power supply off
32: Grid condition unmeet
64: DC under voltage
128: Input over resistance
256: Combination error
512: Comm with inverter error
1024: Tme error
| +|PcsAlarm2L1|| +|PcsAlarm2L2|| +|PcsAlarm2L3|| +|PcsFault1L1|1: Control current overload 100%
2: Control current overload 110%
4: Control current overload 150%
8: Control current overload 200%
16: Control current overload 120%
32: Control current overload 300%
64: Control transient load 300%
128: Grid over current
256: Locking waveform too many times
512: Inverter voltage zero drift error
1024: Grid voltage zero drift error
2048: Control current zero drift error
4096: Inverter current zero drift error
8192: Grid current zero drift error
16384: PDP protection
32768: Hardware control current protection
| +|PcsFault1L2|1: Control current overload 100%
2: Control current overload 110%
4: Control current overload 150%
8: Control current overload 200%
16: Control current overload 120%
32: Control current overload 300%
64: Control transient load 300%
128: Grid over current
256: Locking waveform too many times
512: Inverter voltage zero drift error
1024: Grid voltage zero drift error
2048: Control current zero drift error
4096: Inverter current zero drift error
8192: Grid current zero drift error
16384: PDP protection
32768: Hardware control current protection
| +|PcsFault1L3|1: Control current overload 100%
2: Control current overload 110%
4: Control current overload 150%
8: Control current overload 200%
16: Control current overload 120%
32: Control current overload 300%
64: Control transient load 300%
128: Grid over current
256: Locking waveform too many times
512: Inverter voltage zero drift error
1024: Grid voltage zero drift error
2048: Control current zero drift error
4096: Inverter current zero drift error
8192: Grid current zero drift error
16384: PDP protection
32768: Hardware control current protection
| +|PcsFault2L1|1: Hardware AC volt. protection
2: Hardware DC curr. protection
4: Hardware temperature protection
8: No capturing signal
16: DC overvoltage
32: DC disconnected
64: Inverter undervoltage
128: Inverter overvoltage
256: Current sensor fail
512: Voltage sensor fail
1024: Power uncontrollable
2048: Current uncontrollable
4096: Fan error
8192: Phase lack
16384: Inverter relay fault
32768: Grid relay fault
| +|PcsFault2L2|1: Hardware AC volt. protection
2: Hardware DC curr. protection
4: Hardware temperature protection
8: No capturing signal
16: DC overvoltage
32: DC disconnected
64: Inverter undervoltage
128: Inverter overvoltage
256: Current sensor fail
512: Voltage sensor fail
1024: Power uncontrollable
2048: Current uncontrollable
4096: Fan error
8192: Phase lack
16384: Inverter relay fault
32768: Grid relay fault
| +|PcsFault2L3|1: Hardware AC volt. protection
2: Hardware DC curr. protection
4: Hardware temperature protection
8: No capturing signal
16: DC overvoltage
32: DC disconnected
64: Inverter undervoltage
128: Inverter overvoltage
256: Current sensor fail
512: Voltage sensor fail
1024: Power uncontrollable
2048: Current uncontrollable
4096: Fan error
8192: Phase lack
16384: Inverter relay fault
32768: Grid relay fault
| +|PcsFault3L1|1: Control panel overtemp
2: Power panel overtemp
4: DC input overcurrent
8: Capacitor overtemp
16: Radiator overtemp
32: Transformer overtemp
64: Combination comm error
128: EEPROM error
256: Load current zero drift error
512: Current limit-R error
1024: Phase sync error
2048: External PV current zero drift error
4096: External grid current zero drift error
| +|PcsFault3L2|1: Control panel overtemp
2: Power panel overtemp
4: DC input overcurrent
8: Capacitor overtemp
16: Radiator overtemp
32: Transformer overtemp
64: Combination comm error
128: EEPROM error
256: Load current zero drift error
512: Current limit-R error
1024: Phase sync error
2048: External PV current zero drift error
4096: External grid current zero drift error
| +|PcsFault3L3|1: Control panel overtemp
2: Power panel overtemp
4: DC input overcurrent
8: Capacitor overtemp
16: Radiator overtemp
32: Transformer overtemp
64: Combination comm error
128: EEPROM error
256: Load current zero drift error
512: Current limit-R error
1024: Phase sync error
2048: External PV current zero drift error
4096: External grid current zero drift error
| +|PcsMode|0: Emergency
1: ConsumersPeakPattern
2: Economic
3: Eco
4: Debug
5: SmoothPv
6: Remote
| +|PcsOperationState|0: Self-checking
1: Standby
2: Off grid PV
3: Off grid
4: On-Grid
5: Fail
6: bypass 1
7: bypass 2
| +|PhaseAllowedApparentPower|VA| +|ReactivePowerL1|var| +|ReactivePowerL2|var| +|ReactivePowerL3|var| +|Day|| +|Hour|| +|Minute|| +|Month|| +|Second|| +|Year|| +|SetActivePowerL1|W| +|SetActivePowerL2|W| +|SetActivePowerL3|W| +|SetPcsMode|0: Emergency
1: ConsumersPeakPattern
2: Economic
3: Eco
4: Debug
5: SmoothPv
6: Remote
| +|SetReactivePowerL1|Var| +|SetReactivePowerL2|Var| +|SetReactivePowerL3|Var| +|SetSetupMode|0: Off
1: On
| +|SetWorkState|0: Local control
1: Start
2: Remote control off grid starting
3: Standby
4: Stop
| +|SetupMode|0: Off
1: On
| +|Soc|%| +|SystemState|0: Standby
1: Start Off-Grid
2: Start
3: Fault
4: Off-grid PV
| +|TotalBatteryChargeEnergy|Wh| +|TotalBatteryDischargeEnergy|Wh| +|VoltageL1|mV| +|VoltageL2|mV| +|VoltageL3|mV| +|Warning|| +|WorkMode|2: Economy
6: Remote
8: Timing
| # FENECON Pro Meter diff --git a/edge/src/io/openems/impl/device/pro/WarningEss.java b/edge/src/io/openems/impl/device/pro/WarningEss.java new file mode 100644 index 00000000000..91f67799b2a --- /dev/null +++ b/edge/src/io/openems/impl/device/pro/WarningEss.java @@ -0,0 +1,21 @@ +package io.openems.impl.device.pro; + +import io.openems.api.channel.thingstate.WarningEnum; + +public enum WarningEss implements WarningEnum { + FailTheSystemShouldBeStopped(0), CommonLowVoltageAlarm(1), CommonHighVoltageAlarm(2), ChargingOverCurrentAlarm( + 3), DischargingOverCurrentAlarm(4), OverTemperatureAlarm(5), InteralCommunicationAbnormal(6), GridUndervoltageL1(7), GridOvervoltageL1(8), GridUnderFrequencyL1(9), GridOverFrequencyL1(10), GridPowerSupplyOffL1(11), GridConditionUnmeetL1(12), DCUnderVoltageL1(13), InputOverResistanceL1(14), CombinationErrorL1(15), CommWithInverterErrorL1(16), TmeErrorL1(17), + GridUndervoltageL2(18), GridOvervoltageL2(19), GridUnderFrequencyL2(20), GridOverFrequencyL2(21), GridPowerSupplyOffL2(22), GridConditionUnmeetL2(23), DCUnderVoltageL2(24), InputOverResistanceL2(25), CombinationErrorL2(26), CommWithInverterErrorL2(27), TmeErrorL2(28), + GridUndervoltageL3(29), GridOvervoltageL3(30), GridUnderFrequencyL3(31), GridOverFrequencyL3(32), GridPowerSupplyOffL3(33), GridConditionUnmeetL3(34), DCUnderVoltageL3(35), InputOverResistanceL3(36), CombinationErrorL3(37), CommWithInverterErrorL3(38), TmeErrorL3(39), + OFFGrid(40); + public final int value; + + private WarningEss(int value) { + this.value = value; + } + + @Override + public int getValue() { + return this.value; + } +} diff --git a/edge/src/io/openems/impl/device/pro/WarningPvMeter.java b/edge/src/io/openems/impl/device/pro/WarningPvMeter.java new file mode 100644 index 00000000000..e9752e61bf0 --- /dev/null +++ b/edge/src/io/openems/impl/device/pro/WarningPvMeter.java @@ -0,0 +1,18 @@ +package io.openems.impl.device.pro; + +import io.openems.api.channel.thingstate.WarningEnum; + +public enum WarningPvMeter implements WarningEnum { + NegativePowerL1(0),NegativePowerL2(1),NegativePowerL3(2); + + public final int value; + + private WarningPvMeter(int value) { + this.value = value; + } + + @Override + public int getValue() { + return this.value; + } +} diff --git a/edge/src/io/openems/impl/device/refu/FaultEss.java b/edge/src/io/openems/impl/device/refu/FaultEss.java new file mode 100644 index 00000000000..8628d7a0188 --- /dev/null +++ b/edge/src/io/openems/impl/device/refu/FaultEss.java @@ -0,0 +1,34 @@ +package io.openems.impl.device.refu; + +import io.openems.api.channel.thingstate.FaultEnum; + +public enum FaultEss implements FaultEnum{ + BMSInError(0), BMSInErrorSecond(1), BMSUndervoltage(2), BMSOvercurrent(3), ErrorBMSLimitsNotInitialized(4), ConnectError(5), OvervoltageWarning(6), + UndervoltageWarning(7), OvercurrentWarning(8), BMSReady(9), TREXReady(10), NoEnableBateryGroupOrUsableBatteryGroup(11), NormalLeakageOfBatteryGroup(12), + SeriousLeakageOfBatteryGroup(13), BatteryStartFailure(14), BatteryStopFailure(15), InterruptionOfCANCommunication(16),InterruptionOfCANCommunicationBetweenBatteryGroupAndController(17), + EmergencyStopAbnormalOfAuxiliaryCollector(18), LeakageSelfDetectionOnNegative(19), LeakageSelfDetectionOnPositive(20), SelfDetectionFailureOnBattery(21), + CANCommunicationInterruptionBetweenBatteryGroupAndGroup1(22),CANCommunicationInterruptionBetweenBatteryGroupAndGroup2(23), CANCommunicationInterruptionBetweenBatteryGroupAndGroup3(24), + CANCommunicationInterruptionBetweenBatteryGroupAndGroup4(25), MainContractorAbnormalInBatterySelfDetectGroup1(26), MainContractorAbnormalInBatterySelfDetectGroup2(27), + MainContractorAbnormalInBatterySelfDetectGroup3(28), MainContractorAbnormalInBatterySelfDetectGroup4(29), PreChargeContractorAbnormalOnBatterySelfDetectGroup1(30), + PreChargeContractorAbnormalOnBatterySelfDetectGroup2(31), PreChargeContractorAbnormalOnBatterySelfDetectGroup3(32), PreChargeContractorAbnormalOnBatterySelfDetectGroup4(33), + MainContactFailureOnBatteryControlGroup1(34), MainContactFailureOnBatteryControlGroup2(35), MainContactFailureOnBatteryControlGroup3(36), MainContactFailureOnBatteryControlGroup4(37), + PreChargeFailureOnBatteryControlGroup1(38), PreChargeFailureOnBatteryControlGroup2(39), PreChargeFailureOnBatteryControlGroup3(40), PreChargeFailureOnBatteryControlGroup4(41), + SamplingCircuitAbnormalForBMU(42), PowerCableDisconnectFailure(43), SamplingCircuitDisconnectFailure(44), CANDisconnectForMasterAndSlave(45), SammplingCircuitFailure(46), + SingleBatteryFailure(47), CircuitDetectionAbnormalForMainContactor(48), CircuitDetectionAbnormalForMainContactorSecond(49), CircuitDetectionAbnormalForFancontactor(50), + BMUPowerContactorCircuitDetectionAbnormal(51), CentralContactorCircuitDetectionAbnormal(52), SeriousTemperatureFault(53), CommunicationFaultForSystemController(54), + FrogAlarm(55), FuseFault(56), NormalLeakage(57), SeriousLeakage(58), CANDisconnectionBetweenBatteryGroupAndBatteryStack(59), CentralContactorCircuitOpen(60), + BMUPowerContactorOpen(61); + + + + private final int value; + + private FaultEss(int value) { + this.value = value; + } + + @Override + public int getValue() { + return this.value; + } +} diff --git a/edge/src/io/openems/impl/device/refu/Refu.java b/edge/src/io/openems/impl/device/refu/Refu.java index e3929445abb..510eede1aa9 100644 --- a/edge/src/io/openems/impl/device/refu/Refu.java +++ b/edge/src/io/openems/impl/device/refu/Refu.java @@ -45,7 +45,7 @@ public Refu(Bridge parent) throws OpenemsException { * Config */ @ChannelInfo(title = "Ess", description = "Sets the Ess nature.", type = RefuEss.class) - public final ConfigChannel ess = new ConfigChannel<>("ess", this); + public final ConfigChannel ess = new ConfigChannel("ess", this).addChangeListener(this); /* * Methods diff --git a/edge/src/io/openems/impl/device/refu/RefuEss.java b/edge/src/io/openems/impl/device/refu/RefuEss.java index 7170ff20463..48e42674ff0 100644 --- a/edge/src/io/openems/impl/device/refu/RefuEss.java +++ b/edge/src/io/openems/impl/device/refu/RefuEss.java @@ -24,13 +24,14 @@ import io.openems.api.channel.ReadChannel; import io.openems.api.channel.StaticValueChannel; import io.openems.api.channel.StatusBitChannel; -import io.openems.api.channel.StatusBitChannels; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.ess.AsymmetricEssNature; import io.openems.api.device.nature.ess.SymmetricEssNature; import io.openems.api.doc.ThingInfo; import io.openems.api.exception.ConfigException; +import io.openems.impl.protocol.modbus.ModbusBitWrappingChannel; import io.openems.impl.protocol.modbus.ModbusDeviceNature; import io.openems.impl.protocol.modbus.ModbusReadLongChannel; import io.openems.impl.protocol.modbus.ModbusWriteLongChannel; @@ -57,6 +58,7 @@ public RefuEss(String thingId, Device parent) throws ConfigException { chargeSoc.updateValue((Integer) newValue.get() - 2, false); } }); + this.thingState = new ThingStateChannels(this); } /* @@ -100,8 +102,7 @@ public ConfigChannel chargeSoc() { private StaticValueChannel maxNominalPower = new StaticValueChannel<>("maxNominalPower", this, 100000L) .unit("VA").unit("VA"); private StaticValueChannel capacity = new StaticValueChannel<>("capacity", this, 130000L).unit("Wh"); - public StatusBitChannels warning; - + private ThingStateChannels thingState; /* * This Channels */ @@ -215,11 +216,6 @@ public ReadChannel allowedApparent() { return allowedApparent; } - @Override - public StatusBitChannels warning() { - return warning; - } - @Override public WriteChannel setWorkState() { return setWorkState; @@ -257,39 +253,39 @@ public WriteChannel setReactivePower() { @Override protected ModbusProtocol defineModbusProtocol() throws ConfigException { - warning = new StatusBitChannels("Warning", this); return new ModbusProtocol( // new ModbusInputRegisterRange(0x100, // new UnsignedWordElement(0x100, // systemState = new ModbusReadLongChannel("SystemState", this) // - .label(0, STOP) // - .label(1, "Init") // - .label(2, "Pre-operation") // - .label(3, STANDBY) // - .label(4, START) // - .label(5, FAULT)), - new UnsignedWordElement(0x101, - systemError1 = warning.channel(new StatusBitChannel("SystemError1", this)// - .label(1, "BMS In Error")// - .label(2, "BMS Overvoltage")// - .label(4, "BMS Undervoltage")// - .label(8, "BMS Overcurrent")// - .label(16, "Error BMS Limits not initialized")// - .label(32, "Connect Error")// - .label(64, "Overvoltage warning")// - .label(128, "Undervoltage warning")// - .label(256, "Overcurrent warning")// - .label(512, "BMS Ready")// - .label(1024, "TREX Ready")// - )), + .label(0, STOP) // + .label(1, "Init") // + .label(2, "Pre-operation") // + .label(3, STANDBY) // + .label(4, START) // + .label(5, FAULT)), + new UnsignedWordElement(0x101, // + new ModbusBitWrappingChannel("SystemError1", this, this.thingState)// + .faultBit(0, FaultEss.BMSInError)// + .faultBit(1, FaultEss.BMSInErrorSecond)// + .faultBit(2, FaultEss.BMSUndervoltage)// + .faultBit(3, FaultEss.BMSOvercurrent)// + .faultBit(4, FaultEss.ErrorBMSLimitsNotInitialized)// + .faultBit(5, FaultEss.ConnectError)// + .faultBit(6, FaultEss.OvervoltageWarning)// + .faultBit(7, FaultEss.UndervoltageWarning)// + .faultBit(8, FaultEss.OvercurrentWarning)// + .faultBit(9, FaultEss.BMSReady)// + .faultBit(10, FaultEss.TREXReady)// + ), // + new UnsignedWordElement(0x102, communicationInformations = new StatusBitChannel("CommunicationInformations", this)// - .label(1, "Gateway Initialized")// - .label(2, "Modbus Slave Status")// - .label(4, "Modbus Master Status")// - .label(8, "CAN Timeout")// - .label(16, "First Communication Ok")// - ), new UnsignedWordElement(0x103, inverterStatus = new StatusBitChannel("InverterStatus", this)// + .label(1, "Gateway Initialized")// + .label(2, "Modbus Slave Status")// + .label(4, "Modbus Master Status")// + .label(8, "CAN Timeout")// + .label(16, "First Communication Ok")// + ), new UnsignedWordElement(0x103, inverterStatus = new StatusBitChannel("InverterStatus", this)// .label(1, "Ready to Power on")// .label(2, "Ready for Operating")// .label(4, "Enabled")// @@ -301,22 +297,22 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { .label(4096, "DC relays 1 close")// .label(8192, "DC relays 2 close")// .label(16384, "Mains OK")// - ), new UnsignedWordElement(0x104, errorCode = new ModbusReadLongChannel("ErrorCode", this)), + ), new UnsignedWordElement(0x104, errorCode = new ModbusReadLongChannel("ErrorCode", this)), new UnsignedWordElement(0x105, dcDcStatus = new StatusBitChannel("DCDCStatus", this)// - .label(1, "Ready to Power on")// - .label(2, "Ready for Operating")// - .label(4, "Enabled")// - .label(8, "DCDC Fault")// - .label(128, "DCDC Warning")// - .label(256, "Voltage/Current mode")// - .label(512, "Power mode")// - ), new UnsignedWordElement(0x106, dcDcError = new ModbusReadLongChannel("DCDCError", this)), + .label(1, "Ready to Power on")// + .label(2, "Ready for Operating")// + .label(4, "Enabled")// + .label(8, "DCDC Fault")// + .label(128, "DCDC Warning")// + .label(256, "Voltage/Current mode")// + .label(512, "Power mode")// + ), new UnsignedWordElement(0x106, dcDcError = new ModbusReadLongChannel("DCDCError", this)), new SignedWordElement(0x107, batteryCurrentPcs = new ModbusReadLongChannel("BatteryCurrentPcs", this).unit("mA") - .multiplier(2)), // + .multiplier(2)), // new SignedWordElement(0x108, batteryVoltagePcs = new ModbusReadLongChannel("BatteryVoltagePcs", this).unit("mV") - .multiplier(2)), // + .multiplier(2)), // new SignedWordElement(0x109, current = new ModbusReadLongChannel("Current", this).unit("mA").multiplier(2)), // new SignedWordElement(0x10A, @@ -329,25 +325,25 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { activePower = new ModbusReadLongChannel("ActivePower", this).unit("W").multiplier(2)), // new SignedWordElement(0x10E, activePowerL1 = new ModbusReadLongChannel("ActivePowerL1", this).unit("W") - .multiplier(2)), // + .multiplier(2)), // new SignedWordElement(0x10F, activePowerL2 = new ModbusReadLongChannel("ActivePowerL2", this).unit("W") - .multiplier(2)), // + .multiplier(2)), // new SignedWordElement(0x110, activePowerL3 = new ModbusReadLongChannel("ActivePowerL3", this).unit("W") - .multiplier(2)), // + .multiplier(2)), // new SignedWordElement(0x111, reactivePower = new ModbusReadLongChannel("ReactivePower", this).unit("Var") - .multiplier(2)), // + .multiplier(2)), // new SignedWordElement(0x112, reactivePowerL1 = new ModbusReadLongChannel("ReactivePowerL1", this).unit("Var") - .multiplier(2)), // + .multiplier(2)), // new SignedWordElement(0x113, reactivePowerL2 = new ModbusReadLongChannel("ReactivePowerL2", this).unit("Var") - .multiplier(2)), // + .multiplier(2)), // new SignedWordElement(0x114, reactivePowerL3 = new ModbusReadLongChannel("ReactivePowerL3", this).unit("Var") - .multiplier(2)), // + .multiplier(2)), // new SignedWordElement(0x115, cosPhi3p = new ModbusReadLongChannel("CosPhi3p", this).unit("")), // new SignedWordElement(0x116, cosPhiL1 = new ModbusReadLongChannel("CosPhiL1", this).unit("")), // new SignedWordElement(0x117, cosPhiL2 = new ModbusReadLongChannel("CosPhiL2", this).unit("")), // @@ -355,277 +351,295 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { new ModbusInputRegisterRange(0x11A, // new SignedWordElement(0x11A, pcsAllowedCharge = new ModbusReadLongChannel("PcsAllowedCharge", this).unit("kW") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0x11B, pcsAllowedDischarge = new ModbusReadLongChannel("PcsAllowedDischarge", this).unit("kW") - .multiplier(2)), + .multiplier(2)), new UnsignedWordElement(0x11C, // batteryState = new ModbusReadLongChannel("BatteryState", this)// - .label(0, "Initial")// - .label(1, STOP)// - .label(2, "Starting")// - .label(3, START)// - .label(4, "Stopping")// - .label(5, "Fault")), // + .label(0, "Initial")// + .label(1, STOP)// + .label(2, "Starting")// + .label(3, START)// + .label(4, "Stopping")// + .label(5, "Fault")), // new UnsignedWordElement(0x11D, // batteryMode = new ModbusReadLongChannel("BatteryMode", this).label(0, "Normal Mode")), new SignedWordElement(0x11E, batteryVoltage = new ModbusReadLongChannel("BatteryVoltage", this).unit("mV") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0x11F, batteryCurrent = new ModbusReadLongChannel("BatteryCurrent", this).unit("mA") - .multiplier(2)), + .multiplier(2)), new SignedWordElement(0x120, // batteryPower = new ModbusReadLongChannel("BatteryPower", this).unit("W")// - .multiplier(2)), + .multiplier(2)), new UnsignedWordElement(0x121, // soc = new ModbusReadLongChannel("Soc", this).unit("%")), new UnsignedWordElement(0x122, // allowedChargeCurrent = new ModbusReadLongChannel("AllowedChargeCurrent", this) - .unit("mA")// - .multiplier(2)// - .negate()), + .unit("mA")// + .multiplier(2)// + .negate()), new UnsignedWordElement(0x123, // allowedDischargeCurrent = new ModbusReadLongChannel("AllowedDischargeCurrent", this) - .unit("mA").multiplier(2)), + .unit("mA").multiplier(2)), new UnsignedWordElement(0x124, // allowedCharge = new ModbusReadLongChannel("AllowedCharge", this).unit("W").multiplier(2) - .negate()), + .negate()), new UnsignedWordElement(0x125, // allowedDischarge = new ModbusReadLongChannel("AllowedDischarge", this).unit("W") - .multiplier(2)), + .multiplier(2)), new SignedDoublewordElement(0x126, // batteryChargeEnergy = new ModbusReadLongChannel("BatteryChargeEnergy", this).unit("kWh")).wordorder(WordOrder.LSWMSW), new SignedDoublewordElement(0x128, // batteryDischargeEnergy = new ModbusReadLongChannel( - "BatteryDischargeEnergy", this).unit("kWh")).wordorder(WordOrder.LSWMSW), + "BatteryDischargeEnergy", this) + .unit("kWh")).wordorder(WordOrder.LSWMSW), new UnsignedWordElement(0x12A, // batteryOperationStatus = new StatusBitChannel("BatteryOperationStatus", this) - .label(1, "Battery group 1 operating")// - .label(2, "Battery group 2 operating")// - .label(4, "Battery group 3 operating")// - .label(8, "Battery group 4 operating")), + .label(1, "Battery group 1 operating")// + .label(2, "Battery group 2 operating")// + .label(4, "Battery group 3 operating")// + .label(8, "Battery group 4 operating")), new UnsignedWordElement(0x12B, // batteryHighestVoltage = new ModbusReadLongChannel("BatteryHighestVoltage", this) - .unit("mV")), + .unit("mV")), new UnsignedWordElement(0x12C, // batteryLowestVoltage = new ModbusReadLongChannel("BatteryLowestVoltage", this) - .unit("mV")), + .unit("mV")), new SignedWordElement(0x12D, // batteryHighestTemperature = new ModbusReadLongChannel("BatteryHighestTemperature", this) - .unit("�C")), + .unit("�C")), new SignedWordElement(0x12E, // batteryLowestTemperature = new ModbusReadLongChannel("BatteryLowestTemperature", this) - .unit("�C")), + .unit("�C")), new UnsignedWordElement(0x12F, // batteryStopRequest = new ModbusReadLongChannel("BatteryStopRequest", this)), - new UnsignedWordElement(0x130, - batteryAlarm1 = warning.channel(new StatusBitChannel("BatteryAlarm1", this)// - .label(1, "Normal charging over-current ")// - .label(2, "Charginig current over limit")// - .label(4, "Discharging current over limit")// - .label(8, "Normal high voltage")// - .label(16, "Normal low voltage")// - .label(32, "Abnormal voltage variation")// - .label(64, "Normal high temperature")// - .label(128, "Normal low temperature")// - .label(256, "Abnormal temperature variation")// - .label(512, "Serious high voltage")// - .label(1024, "Serious low voltage")// - .label(2048, "Serious low temperature")// - .label(4096, "Charging serious over current")// - .label(8192, "Discharging serious over current")// - .label(16384, "Abnormal capacity alarm"))), - new UnsignedWordElement(0x131, - batteryAlarm2 = warning.channel(new StatusBitChannel("BatteryAlarm2", this)// - .label(1, "EEPROM parameter failure")// - .label(2, "Switch off inside combined cabinet")// - .label(32, "Should not be connected to grid due to the DC side condition")// - .label(128, "Emergency stop require from system controller"))), - new UnsignedWordElement(0x132, - batteryAlarm3 = warning.channel(new StatusBitChannel("BatteryAlarm3", this)// - .label(1, "Battery group 1 enable and not connected to grid")// - .label(2, "Battery group 2 enable and not connected to grid")// - .label(4, "Battery group 3 enable and not connected to grid")// - .label(8, "Battery group 4 enable and not connected to grid"))), - new UnsignedWordElement(0x133, - batteryAlarm4 = warning.channel(new StatusBitChannel("BatteryAlarm4", this)// - .label(1, "The isolation switch of battery group 1 open")// - .label(2, "The isolation switch of battery group 2 open")// - .label(4, "The isolation switch of battery group 3 open")// - .label(8, "The isolation switch of battery group 4 open"))), - new DummyElement(0x134), + new UnsignedWordElement(0x130, // + new ModbusBitWrappingChannel("BatteryAlarm1", this, this.thingState)// + .warningBit(0, WarningEss.NormalChargingOverCurrent)// + .warningBit(1, WarningEss.CharginigCurrentOverLimit)// + .warningBit(2, WarningEss.DischargingCurrentOverLimit)// + .warningBit(3, WarningEss.NormalHighVoltage)// + .warningBit(4, WarningEss.NormalLowVoltage)// + .warningBit(5, WarningEss.AbnormalVoltageVariation)// + .warningBit(6, WarningEss.NormalHighTemperature)// + .warningBit(7, WarningEss.NormalLowTemperature)// + .warningBit(8, WarningEss.AbnormalTemperatureVariation)// + .warningBit(9, WarningEss.SeriousHighVoltage)// + .warningBit(10, WarningEss.SeriousLowVoltage)// + .warningBit(11, WarningEss.SeriousLowTemperature)// + .warningBit(12, WarningEss.ChargingSeriousOverCurrent)// + .warningBit(13, WarningEss.DischargingSeriousOverCurrent)// + .warningBit(14, WarningEss.AbnormalCapacityAlarm)// + ), // + + new UnsignedWordElement(0x131, // + new ModbusBitWrappingChannel("BatteryAlarm2", this, this.thingState)// + .warningBit(0, WarningEss.EEPROMParameterFailure)// + .warningBit(1, WarningEss.SwitchOfInsideCombinedCabinet) + .warningBit(5, WarningEss.ShouldNotBeConnectedToGridDueToTheDCSideCondition) + .warningBit(7, WarningEss.EmergencyStopRequireFromSystemController)), // + + new UnsignedWordElement(0x132, // + new ModbusBitWrappingChannel("BatteryAlarm3", this, this.thingState)// + .warningBit(0, WarningEss.BatteryGroup1EnableAndNotConnectedToGrid)// + .warningBit(1, WarningEss.BatteryGroup2EnableAndNotConnectedToGrid)// + .warningBit(2, WarningEss.BatteryGroup3EnableAndNotConnectedToGrid)// + .warningBit(3, WarningEss.BatteryGroup4EnableAndNotConnectedToGrid)// + ), // + + new UnsignedWordElement(0x133, // + new ModbusBitWrappingChannel("BatteryAlarm4", this, this.thingState)// + .warningBit(0, WarningEss.TheIsolationSwitchOfBatteryGroup1Open) + .warningBit(1, WarningEss.TheIsolationSwitchOfBatteryGroup2Open) + .warningBit(2, WarningEss.TheIsolationSwitchOfBatteryGroup3Open) + .warningBit(3, WarningEss.TheIsolationSwitchOfBatteryGroup4Open)), // + + new DummyElement(0x134), // new UnsignedWordElement(0x135, - batteryAlarm6 = warning.channel(new StatusBitChannel("BatteryAlarm6", this)// - .label(1, "Balancing sampling failure of battery group 1")// - .label(2, "Balancing sampling failure of battery group 2")// - .label(4, "Balancing sampling failure of battery group 3")// - .label(8, "Balancing sampling failure of battery group 4"))), - new UnsignedWordElement(0x136, - batteryAlarm7 = warning.channel(new StatusBitChannel("BatteryAlarm7", this)// - .label(1, "Balancing control failure of battery group 1")// - .label(2, "Balancing control failure of battery group 2")// - .label(4, "Balancing control failure of battery group 3")// - .label(8, "Balancing control failure of battery group 4"))), - new UnsignedWordElement(0x137, - batteryFault1 = warning.channel(new StatusBitChannel("BatteryFault1", this)// - .label(1, "No enable batery group or usable battery group")// - .label(2, "Normal leakage of battery group")// - .label(4, "Serious leakage of battery group")// - .label(8, "Battery start failure")// - .label(16, "Battery stop failure")// - .label(32, - "Interruption of CAN Communication between battery group and controller")// - .label(1024, "Emergency stop abnormal of auxiliary collector")// - .label(2048, "Leakage self detection on negative")// - .label(4096, "Leakage self detection on positive")// - .label(8192, "Self detection failure on battery"))), - new UnsignedWordElement(0x138, - batteryFault2 = warning.channel(new StatusBitChannel("BatteryFault2", this)// - .label(1, "CAN Communication interruption between battery group and group 1")// - .label(2, "CAN Communication interruption between battery group and group 2")// - .label(4, "CAN Communication interruption between battery group and group 3")// - .label(8, "CAN Communication interruption between battery group and group 4"))), - new UnsignedWordElement(0x139, - batteryFault3 = warning.channel(new StatusBitChannel("BatteryFault3", this)// - .label(1, "Main contractor abnormal in battery self detect group 1")// - .label(2, "Main contractor abnormal in battery self detect group 2")// - .label(4, "Main contractor abnormal in battery self detect group 3")// - .label(8, "Main contractor abnormal in battery self detect group 4"))), - new UnsignedWordElement(0x13A, - batteryFault4 = warning.channel(new StatusBitChannel("BatteryFault4", this)// - .label(1, "Pre-charge contractor abnormal on battery self detect group 1")// - .label(2, "Pre-charge contractor abnormal on battery self detect group 2")// - .label(4, "Pre-charge contractor abnormal on battery self detect group 3")// - .label(8, "Pre-charge contractor abnormal on battery self detect group 4"))), - new UnsignedWordElement(0x13B, - batteryFault5 = warning.channel(new StatusBitChannel("BatteryFault5", this)// - .label(1, "Main contact failure on battery control group 1")// - .label(2, "Main contact failure on battery control group 2")// - .label(4, "Main contact failure on battery control group 3")// - .label(8, "Main contact failure on battery control group 4"))), - new UnsignedWordElement(0x13C, - batteryFault6 = warning.channel(new StatusBitChannel("BatteryFault6", this)// - .label(1, "Pre-charge failure on battery control group 1")// - .label(2, "Pre-charge failure on battery control group 2")// - .label(4, "Pre-charge failure on battery control group 3")// - .label(8, "Pre-charge failure on battery control group 4"))), - new UnsignedWordElement(0x13D, - batteryFault7 = warning.channel(new StatusBitChannel("BatteryFault7", this)// - )), new UnsignedWordElement(0x13E, - batteryFault8 = warning.channel(new StatusBitChannel("BatteryFault8", this)// - )), - new UnsignedWordElement(0x13F, - batteryFault9 = warning.channel(new StatusBitChannel("BatteryFault9", this)// - .label(4, "Sampling circuit abnormal for BMU")// - .label(8, "Power cable disconnect failure")// - .label(16, "Sampling circuit disconnect failure")// - .label(64, "CAN disconnect for master and slave")// - .label(512, "Sammpling circuit failure")// - .label(1024, "Single battery failure")// - .label(2048, "Circuit detection abnormal for main contactor")// - .label(4096, "Circuit detection abnormal for main contactor")// - .label(8192, "Circuit detection abnormal for Fancontactor")// - .label(16384, "BMUPower contactor circuit detection abnormal")// - .label(32768, "Central contactor circuit detection abnormal"))), - new UnsignedWordElement(0x140, - batteryFault10 = warning.channel(new StatusBitChannel("BatteryFault10", this)// - .label(4, "Serious temperature fault")// - .label(8, "Communication fault for system controller")// - .label(128, "Frog alarm")// - .label(256, "Fuse fault")// - .label(1024, "Normal leakage")// - .label(2048, "Serious leakage")// - .label(4096, "CAN disconnection between battery group and battery stack")// - .label(8192, "Central contactor circuit open")// - .label(16384, "BMU power contactor open"))), - new UnsignedWordElement(0x141, - batteryFault11 = warning.channel(new StatusBitChannel("BatteryFault11", this)// - )), new UnsignedWordElement(0x142, - batteryFault12 = warning.channel(new StatusBitChannel("BatteryFault12", this)// - )), + new ModbusBitWrappingChannel("BatteryAlarm6", this, this.thingState)// + .warningBit(0, WarningEss.BalancingSamplingFailureOfBatteryGroup1)// + .warningBit(1, WarningEss.BalancingSamplingFailureOfBatteryGroup2)// + .warningBit(2, WarningEss.BalancingSamplingFailureOfBatteryGroup3)// + .warningBit(3, WarningEss.BalancingSamplingFailureOfBatteryGroup4)// + ), // + + new UnsignedWordElement(0x136, // + new ModbusBitWrappingChannel("BatteryAlarm7", this, this.thingState)// + .warningBit(0, WarningEss.BalancingControlFailureOfBatteryGroup1)// + .warningBit(1, WarningEss.BalancingControlFailureOfBatteryGroup2)// + .warningBit(2, WarningEss.BalancingControlFailureOfBatteryGroup3)// + .warningBit(3, WarningEss.BalancingControlFailureOfBatteryGroup4)// + ), // + + new UnsignedWordElement(0x137, // + new ModbusBitWrappingChannel("BatteryFault1", this, this.thingState)// + .faultBit(0, FaultEss.NoEnableBateryGroupOrUsableBatteryGroup)// + .faultBit(1, FaultEss.NormalLeakageOfBatteryGroup)// + .faultBit(2, FaultEss.SeriousLeakageOfBatteryGroup)// + .faultBit(3, FaultEss.BatteryStartFailure)// + .faultBit(4, FaultEss.BatteryStopFailure)// + .faultBit(5, + FaultEss.InterruptionOfCANCommunicationBetweenBatteryGroupAndController)// + .faultBit(10, FaultEss.EmergencyStopAbnormalOfAuxiliaryCollector)// + .faultBit(11, FaultEss.LeakageSelfDetectionOnNegative)// + .faultBit(12, FaultEss.LeakageSelfDetectionOnPositive)// + .faultBit(13, FaultEss.SelfDetectionFailureOnBattery)// + ), // + + new UnsignedWordElement(0x138, // + new ModbusBitWrappingChannel("BatteryFault2", this, this.thingState)// + .faultBit(0, FaultEss.CANCommunicationInterruptionBetweenBatteryGroupAndGroup1)// + .faultBit(1, FaultEss.CANCommunicationInterruptionBetweenBatteryGroupAndGroup2)// + .faultBit(2, FaultEss.CANCommunicationInterruptionBetweenBatteryGroupAndGroup3)// + .faultBit(3, FaultEss.CANCommunicationInterruptionBetweenBatteryGroupAndGroup4)// + ), // + + new UnsignedWordElement(0x139, // + new ModbusBitWrappingChannel("BatteryFault3", this, this.thingState)// + .faultBit(0, FaultEss.MainContractorAbnormalInBatterySelfDetectGroup1)// + .faultBit(1, FaultEss.MainContractorAbnormalInBatterySelfDetectGroup2)// + .faultBit(2, FaultEss.MainContractorAbnormalInBatterySelfDetectGroup3)// + .faultBit(3, FaultEss.MainContractorAbnormalInBatterySelfDetectGroup4)// + ), // + + new UnsignedWordElement(0x13A, // + new ModbusBitWrappingChannel("BatteryFault4", this, this.thingState)// + .faultBit(0, FaultEss.PreChargeContractorAbnormalOnBatterySelfDetectGroup1)// + .faultBit(1, FaultEss.PreChargeContractorAbnormalOnBatterySelfDetectGroup2)// + .faultBit(2, FaultEss.PreChargeContractorAbnormalOnBatterySelfDetectGroup3)// + .faultBit(3, FaultEss.PreChargeContractorAbnormalOnBatterySelfDetectGroup4)// + ), // + + new UnsignedWordElement(0x13B, // + new ModbusBitWrappingChannel("BatteryFault5", this, this.thingState)// + .faultBit(0, FaultEss.MainContactFailureOnBatteryControlGroup1)// + .faultBit(1, FaultEss.MainContactFailureOnBatteryControlGroup2)// + .faultBit(2, FaultEss.MainContactFailureOnBatteryControlGroup3)// + .faultBit(3, FaultEss.MainContactFailureOnBatteryControlGroup4)// + ), // + + new UnsignedWordElement(0x13C, // + new ModbusBitWrappingChannel("BatteryFault6", this, this.thingState)// + .faultBit(0, FaultEss.PreChargeFailureOnBatteryControlGroup1)// + .faultBit(1, FaultEss.PreChargeFailureOnBatteryControlGroup2)// + .faultBit(2, FaultEss.PreChargeFailureOnBatteryControlGroup3)// + .faultBit(3, FaultEss.PreChargeFailureOnBatteryControlGroup4)// + ), // + + new UnsignedWordElement(0x13D, // + new ModbusBitWrappingChannel("BatteryFault7", this, this.thingState)// + // .faultBit(0, FaultEss)// + ), // + + new UnsignedWordElement(0x13E, // + new ModbusBitWrappingChannel("BatteryFault8", this, this.thingState)// + // .faultBit(0, FaultEss)// + ), // + new UnsignedWordElement(0x13F, // + new ModbusBitWrappingChannel("BatteryFault9", this, this.thingState)// + .faultBit(2, FaultEss.SamplingCircuitAbnormalForBMU)// + .faultBit(3, FaultEss.PowerCableDisconnectFailure)// + .faultBit(4, FaultEss.SamplingCircuitDisconnectFailure)// + .faultBit(6, FaultEss.CANDisconnectForMasterAndSlave)// + .faultBit(9, FaultEss.SammplingCircuitFailure)// + .faultBit(10, FaultEss.SingleBatteryFailure)// + .faultBit(11, FaultEss.CircuitDetectionAbnormalForMainContactor)// + .faultBit(12, FaultEss.CircuitDetectionAbnormalForMainContactorSecond)// + .faultBit(13, FaultEss.CircuitDetectionAbnormalForFancontactor)// + .faultBit(14, FaultEss.BMUPowerContactorCircuitDetectionAbnormal)// + .faultBit(15, FaultEss.CentralContactorCircuitDetectionAbnormal)// + ), // + + new UnsignedWordElement(0x140, // + new ModbusBitWrappingChannel("BatteryFault10", this, this.thingState)// + .faultBit(2, FaultEss.SeriousTemperatureFault)// + .faultBit(3, FaultEss.CommunicationFaultForSystemController)// + .faultBit(7, FaultEss.FrogAlarm)// + .faultBit(8, FaultEss.FuseFault)// + .faultBit(10, FaultEss.NormalLeakage)// + .faultBit(11, FaultEss.SeriousLeakage)// + .faultBit(12, FaultEss.CANDisconnectionBetweenBatteryGroupAndBatteryStack)// + .faultBit(13, FaultEss.CentralContactorCircuitOpen)// + .faultBit(14, FaultEss.BMUPowerContactorOpen)// + ), // + + new UnsignedWordElement(0x141, // + new ModbusBitWrappingChannel("BatteryFault11", this, this.thingState)// + // .faultBit(, FaultEss)// + ), // + + new UnsignedWordElement(0x142, // + new ModbusBitWrappingChannel("BatteryFault12", this, this.thingState)// + // .faultBit(, FaultEss)// + ), // + new UnsignedWordElement(0x143, - batteryFault13 = warning.channel(new StatusBitChannel("BatteryFault13", this)// - )), new UnsignedWordElement(0x144, - batteryFault14 = warning.channel(new StatusBitChannel("BatteryFault14", this)// - )), new UnsignedWordElement(0x145, batteryGroupControlStatus = warning - .channel(new StatusBitChannel("BatteryGroupControlStatus", this)// - )), new UnsignedWordElement(0x146, - errorLog1 = warning.channel(new StatusBitChannel("ErrorLog1", this)// - )), new UnsignedWordElement(0x147, - errorLog2 = warning.channel(new StatusBitChannel("ErrorLog2", this)// - )), new UnsignedWordElement(0x148, - errorLog3 = warning.channel(new StatusBitChannel("ErrorLog3", this)// - )), - new UnsignedWordElement(0x149, - errorLog4 = warning.channel(new StatusBitChannel("ErrorLog4", this)// - )), new UnsignedWordElement(0x14a, - errorLog5 = warning.channel(new StatusBitChannel("ErrorLog5", this)// - )), new UnsignedWordElement(0x14b, - errorLog6 = warning.channel(new StatusBitChannel("ErrorLog6", this)// - )), - new UnsignedWordElement(0x14c, - errorLog7 = warning.channel(new StatusBitChannel("ErrorLog7", this)// - )), new UnsignedWordElement(0x14d, - errorLog8 = warning.channel(new StatusBitChannel("ErrorLog8", this)// - )), new UnsignedWordElement(0x14e, - errorLog9 = warning.channel(new StatusBitChannel("ErrorLog9", this)// - )), - new UnsignedWordElement(0x14f, - errorLog10 = warning.channel(new StatusBitChannel("ErrorLog10", this)// - )), new UnsignedWordElement(0x150, - errorLog11 = warning.channel(new StatusBitChannel("ErrorLog11", this)// - )), new UnsignedWordElement(0x151, - errorLog12 = warning.channel(new StatusBitChannel("ErrorLog12", this)// - )), - new UnsignedWordElement(0x152, - errorLog13 = warning.channel(new StatusBitChannel("ErrorLog13", this)// - )), new UnsignedWordElement(0x153, - errorLog14 = warning.channel(new StatusBitChannel("ErrorLog14", this)// - )), new UnsignedWordElement(0x154, - errorLog15 = warning.channel(new StatusBitChannel("ErrorLog15", this)// - )), - new UnsignedWordElement(0x155, - errorLog16 = warning.channel(new StatusBitChannel("ErrorLog16", this)// - ))), new WriteableModbusRegisterRange(0x200, // - new UnsignedWordElement(0x200, // - setWorkState = new ModbusWriteLongChannel("SetWorkState", this) // - .label(0, STOP) // - .label(1, START)), - new UnsignedWordElement(0x201, // - setSystemErrorReset = new ModbusWriteLongChannel("SetSystemErrorReset", - this)// - .label(0, OFF)// - .label(1, ON)), - new UnsignedWordElement(0x202, // - setOperationMode = new ModbusWriteLongChannel("SetOperationMode", this)// - .label(0, "P/Q Set point")// - .label(1, "IAC / cosphi set point"))), + new ModbusBitWrappingChannel("BatteryFault13", this, this.thingState)// + // .faultBit(, FaultEss)// + ), // + new UnsignedWordElement(0x144, + new ModbusBitWrappingChannel("BatteryFault14", this, this.thingState)// + // .faultBit(, FaultEss)// + ), // + new UnsignedWordElement(0x145, + batteryGroupControlStatus = new StatusBitChannel("BatteryGroupControlStatus", this)// + ), new UnsignedWordElement(0x146, errorLog1 = new StatusBitChannel("ErrorLog1", this)// + ), new UnsignedWordElement(0x147, errorLog2 = new StatusBitChannel("ErrorLog2", this)// + ), new UnsignedWordElement(0x148, errorLog3 = new StatusBitChannel("ErrorLog3", this)// + ), new UnsignedWordElement(0x149, errorLog4 = new StatusBitChannel("ErrorLog4", this)// + ), new UnsignedWordElement(0x14a, errorLog5 = new StatusBitChannel("ErrorLog5", this)// + ), new UnsignedWordElement(0x14b, errorLog6 = new StatusBitChannel("ErrorLog6", this)// + ), new UnsignedWordElement(0x14c, errorLog7 = new StatusBitChannel("ErrorLog7", this)// + ), new UnsignedWordElement(0x14d, errorLog8 = new StatusBitChannel("ErrorLog8", this)// + ), new UnsignedWordElement(0x14e, errorLog9 = new StatusBitChannel("ErrorLog9", this)// + ), new UnsignedWordElement(0x14f, errorLog10 = new StatusBitChannel("ErrorLog10", this)// + ), new UnsignedWordElement(0x150, errorLog11 = new StatusBitChannel("ErrorLog11", this)// + ), new UnsignedWordElement(0x151, errorLog12 = new StatusBitChannel("ErrorLog12", this)// + ), new UnsignedWordElement(0x152, errorLog13 = new StatusBitChannel("ErrorLog13", this)// + ), new UnsignedWordElement(0x153, errorLog14 = new StatusBitChannel("ErrorLog14", this)// + ), new UnsignedWordElement(0x154, errorLog15 = new StatusBitChannel("ErrorLog15", this)// + ), new UnsignedWordElement(0x155, errorLog16 = new StatusBitChannel("ErrorLog16", this)// + )), new WriteableModbusRegisterRange(0x200, // + new UnsignedWordElement(0x200, // + setWorkState = new ModbusWriteLongChannel("SetWorkState", this) // + .label(0, STOP) // + .label(1, START)), + new UnsignedWordElement(0x201, // + setSystemErrorReset = new ModbusWriteLongChannel("SetSystemErrorReset", this)// + .label(0, OFF)// + .label(1, ON)), + new UnsignedWordElement(0x202, // + setOperationMode = new ModbusWriteLongChannel("SetOperationMode", this)// + .label(0, "P/Q Set point")// + .label(1, "IAC / cosphi set point"))), new WriteableModbusRegisterRange(0x203, new SignedWordElement(0x203, // setActivePower = new ModbusWriteLongChannel("SetActivePower", this)// - .unit("W").multiplier(2))), + .unit("W").multiplier(2))), new WriteableModbusRegisterRange(0x204, new SignedWordElement(0x204, // setActivePowerL1 = new ModbusWriteLongChannel("SetActivePowerL1", this)// - .unit("W").multiplier(2)), + .unit("W").multiplier(2)), new SignedWordElement(0x205, // setActivePowerL2 = new ModbusWriteLongChannel("SetActivePowerL2", this)// - .unit("W").multiplier(2)), + .unit("W").multiplier(2)), new SignedWordElement(0x206, // setActivePowerL3 = new ModbusWriteLongChannel("SetActivePowerL3", this)// - .unit("W").multiplier(2))), + .unit("W").multiplier(2))), new WriteableModbusRegisterRange(0x207, new SignedWordElement(0x207, // setReactivePower = new ModbusWriteLongChannel("SetReactivePower", this)// - .unit("W").multiplier(2))), + .unit("W").multiplier(2))), new WriteableModbusRegisterRange(0x208, new SignedWordElement(0x208, // setReactivePowerL1 = new ModbusWriteLongChannel("SetReactivePowerL1", this)// - .unit("W").multiplier(2)), + .unit("W").multiplier(2)), new SignedWordElement(0x209, // setReactivePowerL2 = new ModbusWriteLongChannel("SetReactivePowerL2", this)// - .unit("W").multiplier(2)), + .unit("W").multiplier(2)), new SignedWordElement(0x20A, // setReactivePowerL3 = new ModbusWriteLongChannel("SetReactivePowerL3", this)// - .unit("W").multiplier(2)))); + .unit("W").multiplier(2)))); // new ModbusInputRegisterRange(0x6040, // new UnsignedWordElement(0x6040, // // batteryInformation1 = new ModbusReadLongChannel("BatteryInformation1", this)), @@ -738,4 +752,9 @@ public WriteChannel setReactivePowerL3() { return setReactivePowerL3; } + @Override + public ThingStateChannels getStateChannel() { + return thingState; + } + } diff --git a/edge/src/io/openems/impl/device/refu/WarningEss.java b/edge/src/io/openems/impl/device/refu/WarningEss.java new file mode 100644 index 00000000000..56f0bfef23b --- /dev/null +++ b/edge/src/io/openems/impl/device/refu/WarningEss.java @@ -0,0 +1,29 @@ +package io.openems.impl.device.refu; + +import io.openems.api.channel.thingstate.WarningEnum; + +public enum WarningEss implements WarningEnum +{ + NormalChargingOverCurrent(0), CharginigCurrentOverLimit(1), DischargingCurrentOverLimit(2), NormalHighVoltage(3), NormalLowVoltage(4), + AbnormalVoltageVariation(5), NormalHighTemperature(6), NormalLowTemperature(7), AbnormalTemperatureVariation(8), SeriousHighVoltage(9), + SeriousLowVoltage(10), SeriousLowTemperature(11), ChargingSeriousOverCurrent(12), DischargingSeriousOverCurrent(13), AbnormalCapacityAlarm(14), + EEPROMParameterFailure(15), SwitchOfInsideCombinedCabinet(16), ShouldNotBeConnectedToGridDueToTheDCSideCondition(17), + EmergencyStopRequireFromSystemController(18), BatteryGroup1EnableAndNotConnectedToGrid(19), BatteryGroup2EnableAndNotConnectedToGrid(20), + BatteryGroup3EnableAndNotConnectedToGrid(21), BatteryGroup4EnableAndNotConnectedToGrid(22), TheIsolationSwitchOfBatteryGroup1Open(23), + TheIsolationSwitchOfBatteryGroup2Open(24), TheIsolationSwitchOfBatteryGroup3Open(25), TheIsolationSwitchOfBatteryGroup4Open(26), + BalancingSamplingFailureOfBatteryGroup1(27), BalancingSamplingFailureOfBatteryGroup2(28), BalancingSamplingFailureOfBatteryGroup3(29), + BalancingSamplingFailureOfBatteryGroup4(30), BalancingControlFailureOfBatteryGroup1(31), BalancingControlFailureOfBatteryGroup2(32), + BalancingControlFailureOfBatteryGroup3(33), BalancingControlFailureOfBatteryGroup4(34); + + + public final int value; + + private WarningEss(int value) { + this.value = value; + } + + @Override + public int getValue() { + return this.value; + } +} diff --git a/edge/src/io/openems/impl/device/simulator/FixValueLoadGenerator.java b/edge/src/io/openems/impl/device/simulator/FixValueLoadGenerator.java index 18c2719249f..248e48fe308 100644 --- a/edge/src/io/openems/impl/device/simulator/FixValueLoadGenerator.java +++ b/edge/src/io/openems/impl/device/simulator/FixValueLoadGenerator.java @@ -1,20 +1,27 @@ -package io.openems.impl.device.simulator; - -public class FixValueLoadGenerator implements LoadGenerator { - - private long value; - - public long getValue() { - return value; - } - - public void setValue(long value) { - this.value = value; - } - - @Override - public long getLoad() { - return value; - } - -} +package io.openems.impl.device.simulator; + +import com.google.gson.JsonObject; + +public class FixValueLoadGenerator implements LoadGenerator { + + private long value; + + public long getValue() { + return value; + } + + public void setValue(long value) { + this.value = value; + } + + @Override + public long getLoad() { + return value; + } + + public FixValueLoadGenerator(JsonObject config) { + this.value = config.get("value").getAsLong(); + } + + +} diff --git a/edge/src/io/openems/impl/device/simulator/Simulator.java b/edge/src/io/openems/impl/device/simulator/Simulator.java index 62087affcaf..0cf07affe22 100644 --- a/edge/src/io/openems/impl/device/simulator/Simulator.java +++ b/edge/src/io/openems/impl/device/simulator/Simulator.java @@ -45,24 +45,24 @@ public Simulator(Bridge parent) throws OpenemsException { * Config */ @ChannelInfo(title = "symmetric Ess", description = "Sets the symmetric Ess nature.", type = SimulatorSymmetricEss.class, isOptional = true) - public final ConfigChannel symmetricEss = new ConfigChannel<>("symmetricEss", this); + public final ConfigChannel symmetricEss = new ConfigChannel("symmetricEss", this).addChangeListener(this); @ChannelInfo(title = "asymmetric Ess", description = "Sets the asymmetric Ess nature.", type = SimulatorAsymmetricEss.class, isOptional = true) - public final ConfigChannel asymmetricEss = new ConfigChannel<>("asymmetricEss", this); + public final ConfigChannel asymmetricEss = new ConfigChannel("asymmetricEss", this).addChangeListener(this); @ChannelInfo(title = "Charger", description = "Sets the Charger nature.", type = SimulatorCharger.class, isOptional = true) - public final ConfigChannel charger = new ConfigChannel<>("charger", this); + public final ConfigChannel charger = new ConfigChannel("charger", this).addChangeListener(this); @ChannelInfo(title = "Grid-Meter", description = "Sets the grid meter nature.", type = SimulatorGridMeter.class, isOptional = true) - public final ConfigChannel gridMeter = new ConfigChannel<>("gridMeter", this); + public final ConfigChannel gridMeter = new ConfigChannel("gridMeter", this).addChangeListener(this); @ChannelInfo(title = "Production-Meter", description = "Sets the production meter nature.", type = SimulatorProductionMeter.class, isOptional = true) - public final ConfigChannel productionMeter = new ConfigChannel<>("productionMeter", this); + public final ConfigChannel productionMeter = new ConfigChannel("productionMeter", this).addChangeListener(this); @ChannelInfo(title = "Sps", description = "Sets the Riedmann sps nature.", type = SimulatorRiedmannNature.class, isOptional = true) - public final ConfigChannel sps = new ConfigChannel<>("sps", this); + public final ConfigChannel sps = new ConfigChannel("sps", this).addChangeListener(this); @ChannelInfo(title = "Output", description = "Sets the output nature.", type = SimulatorOutput.class, isOptional = true) - public final ConfigChannel output = new ConfigChannel<>("output", this); + public final ConfigChannel output = new ConfigChannel("output", this).addChangeListener(this); /* * Methods diff --git a/edge/src/io/openems/impl/device/simulator/SimulatorAsymmetricEss.java b/edge/src/io/openems/impl/device/simulator/SimulatorAsymmetricEss.java index 29d60705365..ce4f1c34a49 100644 --- a/edge/src/io/openems/impl/device/simulator/SimulatorAsymmetricEss.java +++ b/edge/src/io/openems/impl/device/simulator/SimulatorAsymmetricEss.java @@ -33,8 +33,8 @@ import io.openems.api.channel.FunctionalReadChannel; import io.openems.api.channel.ReadChannel; import io.openems.api.channel.StaticValueChannel; -import io.openems.api.channel.StatusBitChannels; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.charger.ChargerNature; import io.openems.api.device.nature.ess.AsymmetricEssNature; @@ -59,6 +59,7 @@ public class SimulatorAsymmetricEss extends SimulatorDeviceNature private ThingRepository repo = ThingRepository.getInstance(); private LoadGenerator offGridActivePowerGenerator = new RandomLoadGenerator(); private LoadGenerator offGridReactivePowerGenerator = new RandomLoadGenerator(); + private ThingStateChannels thingState; /* * Constructors @@ -71,6 +72,7 @@ public SimulatorAsymmetricEss(String thingId, Device parent) throws ConfigExcept chargeSoc.updateValue((Integer) newValue.get() - 2, false); } }); + this.thingState = new ThingStateChannels(this); long initialSoc = SimulatorTools.addRandomLong(90, 90, 100, 5); this.energy = capacity.valueOptional().get() / 100 * initialSoc; this.soc = new FunctionalReadChannel("Soc", this, (channels) -> { @@ -123,7 +125,6 @@ public ConfigChannel chargeSoc() { /* * Inherited Channels */ - private StatusBitChannels warning = new StatusBitChannels("Warning", this);; private FunctionalReadChannel soc; private SimulatorReadChannel activePowerL1 = new SimulatorReadChannel<>("ActivePowerL1", this); private SimulatorReadChannel activePowerL2 = new SimulatorReadChannel<>("ActivePowerL2", this); @@ -183,11 +184,6 @@ public WriteChannel setWorkState() { return setWorkState; } - @Override - public StatusBitChannels warning() { - return warning; - } - @Override public ReadChannel allowedApparent() { return allowedApparent; @@ -389,4 +385,9 @@ private void getCharger() { } } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/device/simulator/SimulatorCharger.java b/edge/src/io/openems/impl/device/simulator/SimulatorCharger.java index 2f625d6bc26..27043a93c26 100644 --- a/edge/src/io/openems/impl/device/simulator/SimulatorCharger.java +++ b/edge/src/io/openems/impl/device/simulator/SimulatorCharger.java @@ -24,6 +24,7 @@ import io.openems.api.channel.ReadChannel; import io.openems.api.channel.StaticValueChannel; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.charger.ChargerNature; import io.openems.api.doc.ChannelInfo; @@ -36,11 +37,14 @@ @ThingInfo(title = "Simulator Charger") public class SimulatorCharger extends SimulatorDeviceNature implements ChargerNature { + private ThingStateChannels thingState; + /* * Constructors */ public SimulatorCharger(String thingId, Device parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); } /* @@ -101,4 +105,9 @@ public ReadChannel getInputVoltage() { return voltage; } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/device/simulator/SimulatorGridMeter.java b/edge/src/io/openems/impl/device/simulator/SimulatorGridMeter.java index fbe0016e4a3..236ade71d59 100644 --- a/edge/src/io/openems/impl/device/simulator/SimulatorGridMeter.java +++ b/edge/src/io/openems/impl/device/simulator/SimulatorGridMeter.java @@ -15,6 +15,7 @@ import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.FunctionalReadChannel; import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.ess.AsymmetricEssNature; import io.openems.api.device.nature.ess.EssNature; @@ -59,9 +60,11 @@ public class SimulatorGridMeter extends SimulatorMeter implements ChannelChangeL private List meterNatures = new ArrayList<>(); private LoadGenerator activePowerLoad; private LoadGenerator reactivePowerLoad; + private ThingStateChannels thingState; public SimulatorGridMeter(String thingId, Device parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); repo.addThingChangedListener(new ThingsChangedListener() { @Override @@ -372,4 +375,9 @@ public ReadChannel voltageL3() { return null; } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } \ No newline at end of file diff --git a/edge/src/io/openems/impl/device/simulator/SimulatorOutput.java b/edge/src/io/openems/impl/device/simulator/SimulatorOutput.java index 1189b5c2cd8..e2e97e45a87 100644 --- a/edge/src/io/openems/impl/device/simulator/SimulatorOutput.java +++ b/edge/src/io/openems/impl/device/simulator/SimulatorOutput.java @@ -1,6 +1,7 @@ package io.openems.impl.device.simulator; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.io.OutputNature; import io.openems.api.doc.ThingInfo; @@ -22,12 +23,14 @@ public class SimulatorOutput extends SimulatorDeviceNature implements OutputNatu private SimulatorWriteChannel do9 = new SimulatorWriteChannel<>("DO9", this, false); private SimulatorWriteChannel do10 = new SimulatorWriteChannel<>("DO10", this, false); private SimulatorWriteChannel[] array; + private ThingStateChannels thingState; public SimulatorOutput(String thingId, Device parent) throws ConfigException { super(thingId, parent); @SuppressWarnings("unchecked") SimulatorWriteChannel[] array = new SimulatorWriteChannel[] { do1, do2, do3, do4, do5, do6, do7, do8, do9, do10 }; this.array = array; + this.thingState = new ThingStateChannels(this); } @Override @@ -40,4 +43,9 @@ protected void update() { } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/device/simulator/SimulatorProductionMeter.java b/edge/src/io/openems/impl/device/simulator/SimulatorProductionMeter.java index 8a156b1bf63..350cef2a883 100644 --- a/edge/src/io/openems/impl/device/simulator/SimulatorProductionMeter.java +++ b/edge/src/io/openems/impl/device/simulator/SimulatorProductionMeter.java @@ -11,6 +11,7 @@ import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.FunctionalReadChannel; import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; @@ -36,6 +37,7 @@ public class SimulatorProductionMeter extends SimulatorMeter implements ChannelC private FunctionalReadChannel apparentPower; private LoadGenerator activePowerGenerator; private LoadGenerator reactivePowerGenerator; + private ThingStateChannels thingState; public SimulatorProductionMeter(String thingId, Device parent) throws ConfigException { super(thingId, parent); @@ -43,6 +45,7 @@ public SimulatorProductionMeter(String thingId, Device parent) throws ConfigExce return ControllerUtils.calculateApparentPower(channels[0].valueOptional().orElse(0L), channels[1].valueOptional().orElse(0L)); }, activePower, reactivePower); + this.thingState = new ThingStateChannels(this); } @Override @@ -125,4 +128,9 @@ private LoadGenerator getGenerator(JsonObject config) { return null; } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/device/simulator/SimulatorRiedmannNature.java b/edge/src/io/openems/impl/device/simulator/SimulatorRiedmannNature.java index 493b15de6d8..698a4af4eb5 100644 --- a/edge/src/io/openems/impl/device/simulator/SimulatorRiedmannNature.java +++ b/edge/src/io/openems/impl/device/simulator/SimulatorRiedmannNature.java @@ -27,6 +27,7 @@ import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.ReadChannel; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; @@ -40,11 +41,14 @@ @ThingInfo(title = "Simulator ESS") public class SimulatorRiedmannNature extends SimulatorDeviceNature implements RiedmannNature, ChannelChangeListener { + private ThingStateChannels thingState; + /* * Constructors */ public SimulatorRiedmannNature(String thingId, Device parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); } /* @@ -69,10 +73,10 @@ public SimulatorRiedmannNature(String thingId, Device parent) throws ConfigExcep private ConfigChannel emergencyStop = new ConfigChannel("EmergencyStop", this).defaultValue(0L); @ChannelInfo(title = "SwitchStatePivotPump", type = Long.class) private ConfigChannel switchStatePivotPump = new ConfigChannel("SwitchStatePivotPump", this) - .defaultValue(1L); + .defaultValue(1L); @ChannelInfo(title = "SwitchStatePivotDrive", type = Long.class) private ConfigChannel switchStatePivotDrive = new ConfigChannel("SwitchStatePivotDrive", this) - .defaultValue(1L); + .defaultValue(1L); @ChannelInfo(title = "Error", type = Long.class) private ConfigChannel error = new ConfigChannel("Error", this).defaultValue(0L); private SimulatorReadChannel waterLevelBorehole1On = new SimulatorReadChannel("WaterLevelBorehole1On", @@ -337,4 +341,9 @@ protected void update() { } } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/device/simulator/SimulatorSymmetricEss.java b/edge/src/io/openems/impl/device/simulator/SimulatorSymmetricEss.java index 6bfc603b6b4..37bf03422cc 100644 --- a/edge/src/io/openems/impl/device/simulator/SimulatorSymmetricEss.java +++ b/edge/src/io/openems/impl/device/simulator/SimulatorSymmetricEss.java @@ -35,9 +35,10 @@ import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.FunctionalReadChannel; import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.StaticThingStateChannel; import io.openems.api.channel.StaticValueChannel; -import io.openems.api.channel.StatusBitChannels; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.charger.ChargerNature; import io.openems.api.device.nature.ess.EssNature; @@ -50,6 +51,7 @@ import io.openems.core.ThingRepository; import io.openems.core.utilities.AvgFiFoQueue; import io.openems.core.utilities.ControllerUtils; +import io.openems.impl.protocol.modbus.FaultModbus; import io.openems.impl.protocol.modbus.ModbusWriteLongChannel; import io.openems.impl.protocol.simulator.SimulatorDeviceNature; import io.openems.impl.protocol.simulator.SimulatorReadChannel; @@ -71,12 +73,19 @@ public class SimulatorSymmetricEss extends SimulatorDeviceNature implements Symm "reactivePowerGeneratorConfig", this).addChangeListener(this).addChangeListener(this); private LoadGenerator offGridActivePowerGenerator; private LoadGenerator offGridReactivePowerGenerator; + private ThingStateChannels thingState; /* * Constructors */ public SimulatorSymmetricEss(String thingId, Device parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); + + StaticThingStateChannel tmp = new StaticThingStateChannel(FaultModbus.ConfigurationFault, this, false); + tmp.setValue(true); + thingState.addFaultChannel(tmp); + minSoc.addUpdateListener((channel, newValue) -> { // If chargeSoc was not set -> set it to minSoc minus 2 if (channel == minSoc && !chargeSoc.valueOptional().isPresent()) { @@ -120,10 +129,10 @@ public SimulatorSymmetricEss(String thingId, Device parent) throws ConfigExcepti private ConfigChannel chargeSoc = new ConfigChannel("chargeSoc", this); @ChannelInfo(title = "GridMode", type = Long.class) public ConfigChannel gridMode = new ConfigChannel("gridMode", this).label(0L, ON_GRID) - .label(1L, OFF_GRID).defaultValue(0L); + .label(1L, OFF_GRID).defaultValue(0L); @ChannelInfo(title = "SystemState", type = Long.class) public ConfigChannel systemState = new ConfigChannel("systemState", this) // - .label(1L, START).label(2L, STOP).label(5L, FAULT).defaultValue(1L); + .label(1L, START).label(2L, STOP).label(5L, FAULT).defaultValue(1L); @Override public ConfigChannel minSoc() { @@ -138,7 +147,6 @@ public ConfigChannel chargeSoc() { /* * Inherited Channels */ - private StatusBitChannels warning = new StatusBitChannels("Warning", this);; private FunctionalReadChannel soc; private SimulatorReadChannel activePower = new SimulatorReadChannel("ActivePower", this); private StaticValueChannel allowedApparent = new StaticValueChannel("AllowedApparent", this, 40000L); @@ -212,11 +220,6 @@ public WriteChannel setReactivePower() { return setReactivePower; } - @Override - public StatusBitChannels warning() { - return warning; - } - @Override public ReadChannel allowedApparent() { return allowedApparent; @@ -346,4 +349,9 @@ private void getCharger() { } } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/device/sma/SunnyIsland6.java b/edge/src/io/openems/impl/device/sma/SunnyIsland6.java index b053e3641cf..11acedeb328 100644 --- a/edge/src/io/openems/impl/device/sma/SunnyIsland6.java +++ b/edge/src/io/openems/impl/device/sma/SunnyIsland6.java @@ -22,7 +22,7 @@ public SunnyIsland6(Bridge parent) throws OpenemsException { * Config */ @ChannelInfo(title = "Ess", description = "Sets the Ess nature.", type = SunnyIsland6Ess.class) - public final ConfigChannel ess = new ConfigChannel<>("ess", this); + public final ConfigChannel ess = new ConfigChannel("ess", this).addChangeListener(this); /* * Methods diff --git a/edge/src/io/openems/impl/device/sma/SunnyIsland6Ess.java b/edge/src/io/openems/impl/device/sma/SunnyIsland6Ess.java index 65ffca682df..219b79adb53 100644 --- a/edge/src/io/openems/impl/device/sma/SunnyIsland6Ess.java +++ b/edge/src/io/openems/impl/device/sma/SunnyIsland6Ess.java @@ -3,8 +3,8 @@ import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.ReadChannel; import io.openems.api.channel.StaticValueChannel; -import io.openems.api.channel.StatusBitChannels; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.ess.SymmetricEssNature; import io.openems.api.doc.ChannelInfo; @@ -23,8 +23,11 @@ @ThingInfo(title = "SMA SunnyIsland 6.0H") public class SunnyIsland6Ess extends ModbusDeviceNature implements SymmetricEssNature { + private ThingStateChannels thingState; + public SunnyIsland6Ess(String thingId, Device parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); } /* @@ -44,7 +47,6 @@ public ConfigChannel chargeSoc() { return chargeSoc; } - private StatusBitChannels warning; private ModbusReadLongChannel allowedCharge; private ModbusReadLongChannel allowedDischarge; private ReadChannel gridMode = new StaticValueChannel("GridMode", this, 1L).label(1L, ON_GRID); @@ -113,11 +115,6 @@ public ReadChannel maxNominalPower() { return nominalPower; } - @Override - public StatusBitChannels warning() { - return warning; - } - @Override public WriteChannel setWorkState() { return setControlMode; @@ -150,7 +147,6 @@ public WriteChannel setReactivePower() { @Override protected ModbusProtocol defineModbusProtocol() throws ConfigException { - warning = new StatusBitChannels("Warning", this); ModbusProtocol protokol = new ModbusProtocol( new ModbusRegisterRange(30201, @@ -202,4 +198,9 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { return protokol; } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/device/socomec/Socomec.java b/edge/src/io/openems/impl/device/socomec/Socomec.java index 88a5176ea3b..fa174b9dd3b 100644 --- a/edge/src/io/openems/impl/device/socomec/Socomec.java +++ b/edge/src/io/openems/impl/device/socomec/Socomec.java @@ -45,7 +45,7 @@ public Socomec(Bridge parent) throws OpenemsException { * Config */ @ChannelInfo(title = "Meter", description = "Sets the meter nature.", type = SocomecMeter.class) - public final ConfigChannel meter = new ConfigChannel<>("meter", this); + public final ConfigChannel meter = new ConfigChannel("meter", this).addChangeListener(this); /* * Methods diff --git a/edge/src/io/openems/impl/device/socomec/SocomecB30.java b/edge/src/io/openems/impl/device/socomec/SocomecB30.java index 3b79906bf77..7b2d8a09f80 100644 --- a/edge/src/io/openems/impl/device/socomec/SocomecB30.java +++ b/edge/src/io/openems/impl/device/socomec/SocomecB30.java @@ -45,7 +45,7 @@ public SocomecB30(Bridge parent) throws OpenemsException { * Config */ @ChannelInfo(title = "Meter", description = "Sets the meter nature.", type = SocomecB30Meter.class) - public final ConfigChannel meter = new ConfigChannel<>("meter", this); + public final ConfigChannel meter = new ConfigChannel("meter", this).addChangeListener(this); /* * Methods diff --git a/edge/src/io/openems/impl/device/socomec/SocomecB30Meter.java b/edge/src/io/openems/impl/device/socomec/SocomecB30Meter.java index 20d045c15ce..b077926fbb1 100644 --- a/edge/src/io/openems/impl/device/socomec/SocomecB30Meter.java +++ b/edge/src/io/openems/impl/device/socomec/SocomecB30Meter.java @@ -22,6 +22,7 @@ import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.meter.AsymmetricMeterNature; import io.openems.api.device.nature.meter.SymmetricMeterNature; @@ -38,11 +39,14 @@ @ThingInfo(title = "Socomec B30 Meter") public class SocomecB30Meter extends ModbusDeviceNature implements SymmetricMeterNature, AsymmetricMeterNature { + private ThingStateChannels thingState; + /* * Constructors */ public SocomecB30Meter(String thingId, Device parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); } /* @@ -235,10 +239,15 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { this).unit("kvarh")), new DummyElement(0x4D8B), new UnsignedDoublewordElement(0x4D8C, // reactiveNegativeEnergy = new ModbusReadLongChannel("ReactiveNegativeEnergy", this) - .unit("kvarh")), + .unit("kvarh")), new DummyElement(0x4D8E), new UnsignedDoublewordElement(0x4D8F, // apparentEnergy = new ModbusReadLongChannel("ApparentEnergy", this).unit("kVAh"))) - ); + ); + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; } } diff --git a/edge/src/io/openems/impl/device/socomec/SocomecMeter.java b/edge/src/io/openems/impl/device/socomec/SocomecMeter.java index 8bb51421f6b..83ca75ace23 100644 --- a/edge/src/io/openems/impl/device/socomec/SocomecMeter.java +++ b/edge/src/io/openems/impl/device/socomec/SocomecMeter.java @@ -22,6 +22,7 @@ import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.meter.AsymmetricMeterNature; import io.openems.api.device.nature.meter.SymmetricMeterNature; @@ -38,11 +39,14 @@ @ThingInfo(title = "Socomec Meter") public class SocomecMeter extends ModbusDeviceNature implements SymmetricMeterNature, AsymmetricMeterNature { + private ThingStateChannels thingState; + /* * Constructors */ public SocomecMeter(String thingId, Device parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); } /* @@ -212,28 +216,28 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { activePower = new ModbusReadLongChannel("ActivePower", this).unit("W").multiplier(1)), new SignedDoublewordElement(0xc56A, // reactivePower = new ModbusReadLongChannel("ReactivePower", this).unit("var") - .multiplier(1)), + .multiplier(1)), new SignedDoublewordElement(0xc56C, // apparentPower = new ModbusReadLongChannel("ApparentPower", this).unit("VA") - .multiplier(1)), + .multiplier(1)), new DummyElement(0xc56E, 0xc56F), new SignedDoublewordElement(0xc570, // activePowerL1 = new ModbusReadLongChannel("ActivePowerL1", this).unit("W") - .multiplier(1)), + .multiplier(1)), new SignedDoublewordElement(0xc572, // activePowerL2 = new ModbusReadLongChannel("ActivePowerL2", this).unit("W") - .multiplier(1)), + .multiplier(1)), new SignedDoublewordElement(0xc574, // activePowerL3 = new ModbusReadLongChannel("ActivePowerL3", this).unit("W") - .multiplier(1)), + .multiplier(1)), new SignedDoublewordElement(0xc576, // reactivePowerL1 = new ModbusReadLongChannel("ReactivePowerL1", this).unit("var") - .multiplier(1)), + .multiplier(1)), new SignedDoublewordElement(0xc578, // reactivePowerL2 = new ModbusReadLongChannel("ReactivePowerL2", this).unit("var") - .multiplier(1)), + .multiplier(1)), new SignedDoublewordElement(0xc57A, // reactivePowerL3 = new ModbusReadLongChannel("ReactivePowerL3", this).unit("var") - .multiplier(1))), + .multiplier(1))), new ModbusRegisterRange(0xc652, // new UnsignedDoublewordElement(0xc652, // activePositiveEnergy = new ModbusReadLongChannel( @@ -248,6 +252,11 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { "ActiveNegativeEnergy", this).unit("kWh")), new UnsignedDoublewordElement(0xc65a, // reactiveNegativeEnergy = new ModbusReadLongChannel("ReactiveNegativeEnergy", this) - .unit("kvarh")))); + .unit("kvarh")))); + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; } } diff --git a/edge/src/io/openems/impl/device/socomec/SocomecSinglePhase.java b/edge/src/io/openems/impl/device/socomec/SocomecSinglePhase.java new file mode 100644 index 00000000000..e0d11d28283 --- /dev/null +++ b/edge/src/io/openems/impl/device/socomec/SocomecSinglePhase.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.device.socomec; + +import java.util.HashSet; +import java.util.Set; + +import io.openems.api.bridge.Bridge; +import io.openems.api.channel.ConfigChannel; +import io.openems.api.device.nature.DeviceNature; +import io.openems.api.doc.ChannelInfo; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.OpenemsException; +import io.openems.impl.protocol.modbus.ModbusDevice; + +@ThingInfo(title = "Socomec") +public class SocomecSinglePhase extends ModbusDevice { + + /* + * Constructors + */ + public SocomecSinglePhase(Bridge parent) throws OpenemsException { + super(parent); + } + + /* + * Config + */ + @ChannelInfo(title = "Meter", description = "Sets the meter nature.", type = SocomecSinglePhaseMeter.class) + public final ConfigChannel meter = new ConfigChannel("meter", this).addChangeListener(this); + + /* + * Methods + */ + @Override + protected Set getDeviceNatures() { + Set natures = new HashSet<>(); + if (meter.valueOptional().isPresent()) { + natures.add(meter.valueOptional().get()); + } + return natures; + } + +} diff --git a/edge/src/io/openems/impl/device/socomec/SocomecSinglePhaseMeter.java b/edge/src/io/openems/impl/device/socomec/SocomecSinglePhaseMeter.java new file mode 100644 index 00000000000..3cc6a499b6f --- /dev/null +++ b/edge/src/io/openems/impl/device/socomec/SocomecSinglePhaseMeter.java @@ -0,0 +1,163 @@ +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.device.socomec; + +import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.device.Device; +import io.openems.api.device.nature.meter.SymmetricMeterNature; +import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.ConfigException; +import io.openems.impl.protocol.modbus.ModbusDeviceNature; +import io.openems.impl.protocol.modbus.ModbusReadLongChannel; +import io.openems.impl.protocol.modbus.internal.DummyElement; +import io.openems.impl.protocol.modbus.internal.ModbusProtocol; +import io.openems.impl.protocol.modbus.internal.SignedDoublewordElement; +import io.openems.impl.protocol.modbus.internal.UnsignedDoublewordElement; +import io.openems.impl.protocol.modbus.internal.range.ModbusRegisterRange; + +@ThingInfo(title = "Socomec Single Phase Meter") +public class SocomecSinglePhaseMeter extends ModbusDeviceNature implements SymmetricMeterNature { + + private ThingStateChannels thingState; + + /* + * Constructors + */ + public SocomecSinglePhaseMeter(String thingId, Device parent) throws ConfigException { + super(thingId, parent); + this.thingState = new ThingStateChannels(this); + } + + /* + * Config + */ + private final ConfigChannel type = new ConfigChannel("type", this); + + @Override + public ConfigChannel type() { + return type; + } + + private final ConfigChannel maxActivePower = new ConfigChannel("maxActivePower", this); + + @Override + public ConfigChannel maxActivePower() { + return maxActivePower; + } + + private final ConfigChannel minActivePower = new ConfigChannel("minActivePower", this); + + @Override + public ConfigChannel minActivePower() { + return minActivePower; + } + + /* + * Inherited Channels + */ + private ModbusReadLongChannel activePower; + private ModbusReadLongChannel apparentPower; + private ModbusReadLongChannel reactivePower; + private ModbusReadLongChannel frequency; + private ModbusReadLongChannel voltageL1; + + @Override + public ModbusReadLongChannel activePower() { + return activePower; + } + + @Override + public ModbusReadLongChannel apparentPower() { + return apparentPower; + } + + @Override + public ModbusReadLongChannel reactivePower() { + return reactivePower; + } + + @Override + public ReadChannel frequency() { + return frequency; + } + + /* + * This Channels + */ + public ModbusReadLongChannel activeNegativeEnergy; + public ModbusReadLongChannel activePositiveEnergy; + public ModbusReadLongChannel reactiveNegativeEnergy; + public ModbusReadLongChannel reactivePositiveEnergy; + public ModbusReadLongChannel apparentEnergy; + public ModbusReadLongChannel current; + + /* + * Methods + */ + @Override + protected ModbusProtocol defineModbusProtocol() throws ConfigException { + return new ModbusProtocol( // + new ModbusRegisterRange(0xc558, // + new UnsignedDoublewordElement(0xc558, // + voltageL1 = new ModbusReadLongChannel("VoltageL1", this).unit("mV").multiplier(1)), + new DummyElement(0xc55A, 0xc55D), + new UnsignedDoublewordElement(0xc55E, // + frequency = new ModbusReadLongChannel("Frequency", this).unit("mHZ").multiplier(1)), + new DummyElement(0xc560, 0xc565), + new UnsignedDoublewordElement(0xc566, // + current = new ModbusReadLongChannel("Current", this).unit("mA")), + new SignedDoublewordElement(0xc568, // + activePower = new ModbusReadLongChannel("ActivePower", this).unit("W").multiplier(1)), + new SignedDoublewordElement(0xc56A, // + reactivePower = new ModbusReadLongChannel("ReactivePower", this).unit("var") + .multiplier(1)), + new SignedDoublewordElement(0xc56C, // + apparentPower = new ModbusReadLongChannel("ApparentPower", this).unit("VA") + .multiplier(1))), + new ModbusRegisterRange(0xc652, // + new UnsignedDoublewordElement(0xc652, // + activePositiveEnergy = new ModbusReadLongChannel( + "ActivePositiveEnergy", this).unit("kWh")), + new UnsignedDoublewordElement(0xc654, // + reactivePositiveEnergy = new ModbusReadLongChannel( + "ReactivePositiveEnergy", this).unit("kvarh")), + new UnsignedDoublewordElement(0xc656, // + apparentEnergy = new ModbusReadLongChannel("ApparentEnergy", this).unit("kVAh")), + new UnsignedDoublewordElement(0xc658, // + activeNegativeEnergy = new ModbusReadLongChannel( + "ActiveNegativeEnergy", this).unit("kWh")), + new UnsignedDoublewordElement(0xc65a, // + reactiveNegativeEnergy = new ModbusReadLongChannel("ReactiveNegativeEnergy", this) + .unit("kvarh")))); + } + + @Override + public ReadChannel voltage() { + return this.voltageL1; + } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } +} diff --git a/edge/src/io/openems/impl/device/spanner/BHKW.java b/edge/src/io/openems/impl/device/spanner/BHKW.java index a5573116272..822f1c38e63 100644 --- a/edge/src/io/openems/impl/device/spanner/BHKW.java +++ b/edge/src/io/openems/impl/device/spanner/BHKW.java @@ -45,7 +45,7 @@ public BHKW(Bridge parent) throws OpenemsException { * Config */ @ChannelInfo(title = "Meter", description = "Sets the meter nature.", type = BHKWMeter.class) - public final ConfigChannel meter = new ConfigChannel<>("meter", this); + public final ConfigChannel meter = new ConfigChannel("meter", this).addChangeListener(this); /* * Methods diff --git a/edge/src/io/openems/impl/device/spanner/BHKWMeter.java b/edge/src/io/openems/impl/device/spanner/BHKWMeter.java index b262692ef76..5e27ebf68cc 100644 --- a/edge/src/io/openems/impl/device/spanner/BHKWMeter.java +++ b/edge/src/io/openems/impl/device/spanner/BHKWMeter.java @@ -24,6 +24,7 @@ import io.openems.api.channel.FunctionalReadChannel; import io.openems.api.channel.FunctionalReadChannelFunction; import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.meter.AsymmetricMeterNature; import io.openems.api.device.nature.meter.SymmetricMeterNature; @@ -41,11 +42,14 @@ @ThingInfo(title = "BHKW Meter") public class BHKWMeter extends ModbusDeviceNature implements AsymmetricMeterNature, SymmetricMeterNature { + private ThingStateChannels thingState; + /* * Constructors */ public BHKWMeter(String thingId, Device parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); } /* @@ -293,4 +297,9 @@ public ReadChannel frequency() { public ReadChannel voltage() { return voltageL1; } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } } diff --git a/edge/src/io/openems/impl/device/spanner/Readme.md b/edge/src/io/openems/impl/device/spanner/Readme.md new file mode 100644 index 00000000000..42d4bdc7fdf --- /dev/null +++ b/edge/src/io/openems/impl/device/spanner/Readme.md @@ -0,0 +1,32 @@ +# BHKW Meter + + +Following Values are implemented: + +|ChannelName|Unit| +|---|---| +|ActivePower|| +|ActivePowerL1|W| +|ActivePowerL2|W| +|ActivePowerL3|W| +|alias|| +|ApparentPower|| +|CosPhiL1|| +|CosPhiL2|| +|SocPhiL3|| +|CurrentL1|mA| +|CurrentL2|mA| +|CurrentL3|mA| +|FrequencyL3|mHZ| +|FrequencyL3|mHZ| +|maxActivePower|| +|minActivePower|| +|ReactivePower|| +|ReactivePowerL1|| +|ReactivePowerL2|| +|ReactivePowerL3|| +|type|| +|VoltageL1|mV| +|VoltageL1|mV| +|VoltageL2|mV| +|VoltageL3|mV| diff --git a/edge/src/io/openems/impl/device/studer/StuderVs70.java b/edge/src/io/openems/impl/device/studer/StuderVs70.java index 9e4bb00d9ce..ffbc9eb2b35 100644 --- a/edge/src/io/openems/impl/device/studer/StuderVs70.java +++ b/edge/src/io/openems/impl/device/studer/StuderVs70.java @@ -25,7 +25,7 @@ public StuderVs70(Bridge parent) throws OpenemsException { * Config */ @ChannelInfo(title = "Charger", description = "Sets the charger nature.", type = StuderVs70Charger.class) - public final ConfigChannel charger = new ConfigChannel<>("charger", this); + public final ConfigChannel charger = new ConfigChannel("charger", this).addChangeListener(this); /* * Methods diff --git a/edge/src/io/openems/impl/device/studer/StuderVs70Charger.java b/edge/src/io/openems/impl/device/studer/StuderVs70Charger.java index fa667a46dc3..191d7ce56b9 100644 --- a/edge/src/io/openems/impl/device/studer/StuderVs70Charger.java +++ b/edge/src/io/openems/impl/device/studer/StuderVs70Charger.java @@ -3,6 +3,7 @@ import io.openems.api.channel.ReadChannel; import io.openems.api.channel.StaticValueChannel; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.doc.ThingInfo; import io.openems.api.exception.ConfigException; @@ -15,11 +16,14 @@ @ThingInfo(title = "Studer VS-70 Charger") public class StuderVs70Charger extends StuderDeviceNature { + private ThingStateChannels thingState; + /* * Constructors */ public StuderVs70Charger(String thingId, Device parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); } /* @@ -76,4 +80,9 @@ protected StuderProtocol defineStuderProtocol() throws ConfigException { return p; } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/device/system/System.java b/edge/src/io/openems/impl/device/system/System.java index 228b451a18f..6ddaefdf2d9 100644 --- a/edge/src/io/openems/impl/device/system/System.java +++ b/edge/src/io/openems/impl/device/system/System.java @@ -49,20 +49,20 @@ public System(Bridge parent) throws OpenemsException { * Config */ @ChannelInfo(title = "System", description = "Sets the system nature.", type = SystemNature.class) - public final ConfigChannel system = new ConfigChannel<>("system", this); + public final ConfigChannel system = new ConfigChannel("system", this).addChangeListener(this); @ChannelInfo(title = "Debug", description = "Enables DebugChannels to write into database", type = Boolean.class, isOptional = true, defaultValue = "false") public final ConfigChannel debug = new ConfigChannel("debug", this) - .addChangeListener(new ChannelChangeListener() { + .addChangeListener(new ChannelChangeListener() { - @Override - public void channelChanged(Channel channel, Optional newValue, Optional oldValue) { - if (newValue.isPresent() && (boolean) newValue.get()) { - DebugChannel.enableDebug(); - } else { - DebugChannel.disableDebug(); - } - } - }); + @Override + public void channelChanged(Channel channel, Optional newValue, Optional oldValue) { + if (newValue.isPresent() && (boolean) newValue.get()) { + DebugChannel.enableDebug(); + } else { + DebugChannel.disableDebug(); + } + } + }); /* * Methods diff --git a/edge/src/io/openems/impl/device/system/SystemNature.java b/edge/src/io/openems/impl/device/system/SystemNature.java index b62607f941a..029145e4386 100644 --- a/edge/src/io/openems/impl/device/system/SystemNature.java +++ b/edge/src/io/openems/impl/device/system/SystemNature.java @@ -32,6 +32,7 @@ import io.openems.api.channel.ReadChannel; import io.openems.api.channel.StaticValueChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.doc.ThingInfo; import io.openems.api.exception.ConfigException; @@ -42,6 +43,8 @@ @ThingInfo(title = "Operating system") public class SystemNature extends SystemDeviceNature implements io.openems.api.device.nature.system.SystemNature { + private ThingStateChannels thingState; + /* * Constructors */ @@ -51,12 +54,13 @@ public SystemNature(String thingId, Device parent) throws ConfigException { OPENEMS_STATIC_IPS = new Inet4Address[] { // // 192.168.100.100 (Inet4Address) InetAddress - .getByAddress(new byte[] { (byte) 192, (byte) 168, (byte) 100, (byte) 100 }), + .getByAddress(new byte[] { (byte) 192, (byte) 168, (byte) 100, (byte) 100 }), // 10.4.0.1 (Inet4Address) InetAddress.getByAddress(new byte[] { (byte) 10, (byte) 4, (byte) 0, (byte) 1 }) }; } catch (UnknownHostException e) { throw new ConfigException("Error initializing OpenEMS Static IP: " + e.getMessage()); } + this.thingState = new ThingStateChannels(this); } /* @@ -151,4 +155,9 @@ public void init() { listener.thingChannelsUpdated(this); } } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } } diff --git a/edge/src/io/openems/impl/device/system/asymmetricsymmetriccombinationess/AsymmetricSymmetricCombinationEss.java b/edge/src/io/openems/impl/device/system/asymmetricsymmetriccombinationess/AsymmetricSymmetricCombinationEss.java index 0ec3354d17b..1ce4f9d9560 100644 --- a/edge/src/io/openems/impl/device/system/asymmetricsymmetriccombinationess/AsymmetricSymmetricCombinationEss.java +++ b/edge/src/io/openems/impl/device/system/asymmetricsymmetriccombinationess/AsymmetricSymmetricCombinationEss.java @@ -15,7 +15,7 @@ public class AsymmetricSymmetricCombinationEss extends SystemDevice { @ChannelInfo(title = "AsymmetricSymmetricCombinationEss", description = "Sets the wrapper nature to use asymmetric and symmetric controller together.", type = AsymmetricSymmetricCombinationEssNature.class) - public final ConfigChannel wrapper = new ConfigChannel<>("wrapper", this); + public final ConfigChannel wrapper = new ConfigChannel("wrapper", this).addChangeListener(this); public AsymmetricSymmetricCombinationEss(Bridge parent) throws OpenemsException { super(parent); @@ -30,5 +30,4 @@ protected Set getDeviceNatures() { } return natures; } - } diff --git a/edge/src/io/openems/impl/device/system/asymmetricsymmetriccombinationess/AsymmetricSymmetricCombinationEssNature.java b/edge/src/io/openems/impl/device/system/asymmetricsymmetriccombinationess/AsymmetricSymmetricCombinationEssNature.java index 41271b0cfc2..a46086eb092 100644 --- a/edge/src/io/openems/impl/device/system/asymmetricsymmetriccombinationess/AsymmetricSymmetricCombinationEssNature.java +++ b/edge/src/io/openems/impl/device/system/asymmetricsymmetriccombinationess/AsymmetricSymmetricCombinationEssNature.java @@ -15,8 +15,8 @@ import io.openems.api.channel.FunctionalWriteChannelFunction; import io.openems.api.channel.ProxyReadChannel; import io.openems.api.channel.ReadChannel; -import io.openems.api.channel.StatusBitChannels; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.ess.AsymmetricEssNature; import io.openems.api.device.nature.ess.EssNature; @@ -47,6 +47,8 @@ public class AsymmetricSymmetricCombinationEssNature extends SystemDeviceNature private ThingRepository repo; private List listeners; + private ThingStateChannels state = new ThingStateChannels(this); + private ProxyReadChannel gridMode = new ProxyReadChannel<>("GridMode", this); private ProxyReadChannel soc = new ProxyReadChannel<>("Soc", this); private ProxyReadChannel allowedCharge = new ProxyReadChannel("AllowedCharge", this); @@ -906,11 +908,6 @@ public ReadChannel maxNominalPower() { return maxNominalPower; } - @Override - public StatusBitChannels warning() { - return null; - } - @Override public WriteChannel setWorkState() { return setWorkState; @@ -1482,4 +1479,9 @@ public void onBridgeInitialized() { loadEss(); } + @Override + public ThingStateChannels getStateChannel() { + return this.state; + } + } diff --git a/edge/src/io/openems/impl/device/system/esscluster/EssCluster.java b/edge/src/io/openems/impl/device/system/esscluster/EssCluster.java index c0f27d662e7..d1755ee83d3 100644 --- a/edge/src/io/openems/impl/device/system/esscluster/EssCluster.java +++ b/edge/src/io/openems/impl/device/system/esscluster/EssCluster.java @@ -15,7 +15,7 @@ public class EssCluster extends SystemDevice { @ChannelInfo(title = "EssCluster", description = "Sets the cluster nature.", type = EssClusterNature.class) - public final ConfigChannel cluster = new ConfigChannel<>("cluster", this); + public final ConfigChannel cluster = new ConfigChannel("cluster", this).addChangeListener(this); public EssCluster(Bridge parent) throws OpenemsException { super(parent); diff --git a/edge/src/io/openems/impl/device/system/esscluster/EssClusterNature.java b/edge/src/io/openems/impl/device/system/esscluster/EssClusterNature.java index de43b638952..2492c0e5ce2 100644 --- a/edge/src/io/openems/impl/device/system/esscluster/EssClusterNature.java +++ b/edge/src/io/openems/impl/device/system/esscluster/EssClusterNature.java @@ -19,8 +19,8 @@ import io.openems.api.channel.FunctionalWriteChannel; import io.openems.api.channel.FunctionalWriteChannelFunction; import io.openems.api.channel.ReadChannel; -import io.openems.api.channel.StatusBitChannels; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.DeviceNature; import io.openems.api.device.nature.ess.EssNature; @@ -41,6 +41,7 @@ public class EssClusterNature extends SystemDeviceNature implements SymmetricEss private final Logger log = LoggerFactory.getLogger(EssClusterNature.class); private List listeners; + private ThingStateChannels thingState; private static ThingRepository repo = ThingRepository.getInstance(); @@ -185,7 +186,6 @@ public class EssClusterNature extends SystemDeviceNature implements SymmetricEss } return 1L; }).label(0L, EssNature.STOP).label(1L, EssNature.START).label(2L, EssNature.FAULT).label(3L, "UNDEFINED"); - private StatusBitChannels warning = new StatusBitChannels("Warning", this); private FunctionalWriteChannel setWorkState = new FunctionalWriteChannel("SetWorkState", this, new FunctionalWriteChannelFunction() { @@ -495,6 +495,7 @@ public EssClusterNature(String id, Device parent) throws ConfigException { super(id, parent); this.listeners = new ArrayList<>(); Config.getInstance().addBridgeInitializedEventListener(this); + this.thingState = new ThingStateChannels(this); } @Override @@ -542,11 +543,6 @@ public ReadChannel allowedApparent() { return allowedApparent; } - @Override - public StatusBitChannels warning() { - return warning; - } - @Override public WriteChannel setWorkState() { return setWorkState; @@ -625,6 +621,7 @@ private void loadEss() { setWorkState.removeChannel(ess.setWorkState()); setActivePower.removeChannel(ess.setActivePower()); setReactivePower.removeChannel(ess.setReactivePower()); + thingState.removeChildChannel(ess.getStateChannel()); } essList.clear(); if (essIds != null && isInitialized) { @@ -647,6 +644,7 @@ private void loadEss() { setWorkState.addChannel(ess.setWorkState()); setActivePower.addChannel(ess.setActivePower()); setReactivePower.addChannel(ess.setReactivePower()); + this.thingState.addChildChannel(ess.getStateChannel()); } } } @@ -682,4 +680,9 @@ public void onBridgeInitialized() { loadEss(); } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/device/system/metercluster/MeterCluster.java b/edge/src/io/openems/impl/device/system/metercluster/MeterCluster.java index 11922b18326..d4f4d6ba76b 100644 --- a/edge/src/io/openems/impl/device/system/metercluster/MeterCluster.java +++ b/edge/src/io/openems/impl/device/system/metercluster/MeterCluster.java @@ -15,7 +15,7 @@ public class MeterCluster extends SystemDevice { @ChannelInfo(title = "EssCluster", description = "Sets the cluster nature.", type = MeterClusterNature.class) - public final ConfigChannel cluster = new ConfigChannel<>("cluster", this); + public final ConfigChannel cluster = new ConfigChannel("cluster", this).addChangeListener(this); public MeterCluster(Bridge parent) throws OpenemsException { super(parent); diff --git a/edge/src/io/openems/impl/device/system/metercluster/MeterClusterNature.java b/edge/src/io/openems/impl/device/system/metercluster/MeterClusterNature.java index 97aea56418c..e45deb67969 100644 --- a/edge/src/io/openems/impl/device/system/metercluster/MeterClusterNature.java +++ b/edge/src/io/openems/impl/device/system/metercluster/MeterClusterNature.java @@ -14,6 +14,7 @@ import io.openems.api.channel.ChannelChangeListener; import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.meter.AsymmetricMeterNature; import io.openems.api.device.nature.meter.SymmetricMeterNature; @@ -30,13 +31,14 @@ @ThingInfo(title = "Meter Cluster") public class MeterClusterNature extends SimulatorDeviceNature - implements SymmetricMeterNature, AsymmetricMeterNature, ChannelChangeListener { +implements SymmetricMeterNature, AsymmetricMeterNature, ChannelChangeListener { private final Logger log; private List listeners; private ThingRepository repo; private List symmetricMeterList = new ArrayList<>(); private List asymmetricMeterList = new ArrayList<>(); + private ThingStateChannels thingState; /* * Channels @@ -62,9 +64,10 @@ public class MeterClusterNature extends SimulatorDeviceNature public MeterClusterNature(String thingId, Device parent) throws ConfigException { super(thingId, parent); - log = LoggerFactory.getLogger(this.getClass()); + this.log = LoggerFactory.getLogger(this.getClass()); this.listeners = new ArrayList<>(); this.repo = ThingRepository.getInstance(); + this.thingState = new ThingStateChannels(this); } /* @@ -383,7 +386,13 @@ private void loadMeter() { // remove old ess synchronized (symmetricMeterList) { synchronized (asymmetricMeterList) { + for(SymmetricMeterNature meter: symmetricMeterList) { + this.thingState.removeChildChannel(meter.getStateChannel()); + } symmetricMeterList.clear(); + for(AsymmetricMeterNature meter: asymmetricMeterList) { + this.thingState.removeChangeListener(meter.getStateChannel()); + } asymmetricMeterList.clear(); if (meterIds != null) { for (JsonElement id : meterIds) { @@ -392,9 +401,11 @@ private void loadMeter() { if (nature.get() instanceof AsymmetricMeterNature) { AsymmetricMeterNature meter = (AsymmetricMeterNature) nature.get(); asymmetricMeterList.add(meter); + this.thingState.addChildChannel(meter.getStateChannel()); } else if (nature.get() instanceof SymmetricMeterNature) { SymmetricMeterNature meter = (SymmetricMeterNature) nature.get(); symmetricMeterList.add(meter); + this.thingState.addChildChannel(meter.getStateChannel()); } else { log.error("ThingID: " + id.getAsString() + " is no Meter!"); } @@ -428,4 +439,9 @@ public void removeListener(ThingChannelsUpdatedListener listener) { this.listeners.remove(listener); } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/device/wago/WagoFB.java b/edge/src/io/openems/impl/device/wago/WagoFB.java index 0f4f812f831..62219f84c3d 100644 --- a/edge/src/io/openems/impl/device/wago/WagoFB.java +++ b/edge/src/io/openems/impl/device/wago/WagoFB.java @@ -169,7 +169,7 @@ public static HashMap> getConfig(Inet4Address ip) throws Co break; default: LoggerFactory.getLogger(WagoFB.class) - .debug("ChannelType: " + channelName + " nicht erkannt"); + .debug("ChannelType: " + channelName + " nicht erkannt"); break; } channels.get(channelType).add(channelName); diff --git a/edge/src/io/openems/impl/device/wago/WagoFBInput.java b/edge/src/io/openems/impl/device/wago/WagoFBInput.java index 3442befc43a..0eed423e80b 100644 --- a/edge/src/io/openems/impl/device/wago/WagoFBInput.java +++ b/edge/src/io/openems/impl/device/wago/WagoFBInput.java @@ -26,6 +26,7 @@ import java.util.List; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.io.InputNature; import io.openems.api.doc.ChannelInfo; @@ -47,6 +48,7 @@ public class WagoFBInput extends ModbusDeviceNature implements InputNature { */ public WagoFBInput(String thingId, Device parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); } /* @@ -60,6 +62,8 @@ public WagoFBInput(String thingId, Device parent) throws ConfigException { */ private List channel = new ArrayList<>(); + private ThingStateChannels thingState; + /* * Methods */ @@ -95,7 +99,7 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { elements.toArray(new CoilElement[elements.size()]))); } } - break; + break; } } } catch (InvalidValueException e) { @@ -105,4 +109,8 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { return protocol; } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } } diff --git a/edge/src/io/openems/impl/device/wago/WagoFBOutput.java b/edge/src/io/openems/impl/device/wago/WagoFBOutput.java index 8bbb9ceca13..374cc902e04 100644 --- a/edge/src/io/openems/impl/device/wago/WagoFBOutput.java +++ b/edge/src/io/openems/impl/device/wago/WagoFBOutput.java @@ -26,6 +26,7 @@ import java.util.List; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.io.OutputNature; import io.openems.api.doc.ChannelInfo; @@ -48,6 +49,7 @@ public class WagoFBOutput extends ModbusDeviceNature implements OutputNature { */ public WagoFBOutput(String thingId, Device parent) throws ConfigException { super(thingId, parent); + this.thingState = new ThingStateChannels(this); } /* @@ -61,6 +63,8 @@ public WagoFBOutput(String thingId, Device parent) throws ConfigException { */ private List channel = new ArrayList<>(); + private ThingStateChannels thingState; + /* * Methods */ @@ -96,7 +100,7 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { elements.toArray(new CoilElement[elements.size()]))); } } - break; + break; } } } catch (InvalidValueException e) { @@ -106,4 +110,8 @@ protected ModbusProtocol defineModbusProtocol() throws ConfigException { return protocol; } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } } diff --git a/edge/src/io/openems/impl/persistence/fenecon/FeneconPersistence.java b/edge/src/io/openems/impl/persistence/fenecon/FeneconPersistence.java index 682750d4a8d..77d95a570c6 100644 --- a/edge/src/io/openems/impl/persistence/fenecon/FeneconPersistence.java +++ b/edge/src/io/openems/impl/persistence/fenecon/FeneconPersistence.java @@ -40,6 +40,7 @@ import io.openems.api.channel.ChannelChangeListener; import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.ThingMap; import io.openems.api.device.nature.DeviceNature; import io.openems.api.doc.ChannelInfo; @@ -50,6 +51,7 @@ import io.openems.api.thing.Thing; import io.openems.common.session.Role; import io.openems.common.types.ChannelAddress; +import io.openems.common.types.ChannelEnum; import io.openems.common.types.FieldValue; import io.openems.common.types.NullFieldValue; import io.openems.common.types.NumberFieldValue; @@ -66,6 +68,8 @@ @ThingInfo(title = "FENECON Persistence", description = "Establishes the connection to FENECON Cloud.") public class FeneconPersistence extends Persistence implements ChannelChangeListener { + private ThingStateChannels thingState; + private final static String DEFAULT_CONFIG_LANGUAGE = "en"; /* @@ -96,6 +100,7 @@ public class FeneconPersistence extends Persistence implements ChannelChangeList */ public FeneconPersistence() { this.websocketHandler = new EdgeWebsocketHandler(); + this.thingState = new ThingStateChannels(this); this.reconnectingWebsocket = new ReconnectingWebsocket(this.websocketHandler, (websocket) -> { /* * onOpen @@ -325,6 +330,8 @@ private void addChannelValueToQueue(Channel channel, Optional valueOpt) { fieldValue = new StringFieldValue(((Inet4Address) value).getHostAddress()); } else if (value instanceof Boolean) { fieldValue = new NumberFieldValue(((Boolean) value) ? 1 : 0); + } else if (value instanceof ChannelEnum) { + fieldValue = new NumberFieldValue(((ChannelEnum)value).getValue()); } else if (value instanceof DeviceNature || value instanceof JsonElement || value instanceof Map || value instanceof Set || value instanceof List || value instanceof ThingMap) { // ignore @@ -374,4 +381,9 @@ private Optional proxyInfo() { return Optional.empty(); } } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } } \ No newline at end of file diff --git a/edge/src/io/openems/impl/persistence/influxdb/InfluxdbPersistence.java b/edge/src/io/openems/impl/persistence/influxdb/InfluxdbPersistence.java index 53f17164c21..cebf89320a3 100644 --- a/edge/src/io/openems/impl/persistence/influxdb/InfluxdbPersistence.java +++ b/edge/src/io/openems/impl/persistence/influxdb/InfluxdbPersistence.java @@ -39,16 +39,20 @@ import io.openems.api.channel.ChannelUpdateListener; import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; import io.openems.api.exception.OpenemsException; import io.openems.api.persistence.QueryablePersistence; +import io.openems.common.types.ChannelEnum; import io.openems.common.utils.InfluxdbUtils; import io.openems.core.Databus; @ThingInfo(title = "InfluxDB Persistence", description = "Persists data in an InfluxDB time-series database.") public class InfluxdbPersistence extends QueryablePersistence implements ChannelUpdateListener { + private ThingStateChannels thingState; + /* * Config */ @@ -70,6 +74,10 @@ public class InfluxdbPersistence extends QueryablePersistence implements Channel @ChannelInfo(title = "Sets the duration of each cycle in milliseconds", type = Integer.class) public ConfigChannel cycleTime = new ConfigChannel("cycleTime", this).defaultValue(10000); + public InfluxdbPersistence() { + this.thingState = new ThingStateChannels(this); + } + /* * Fields */ @@ -100,6 +108,8 @@ public void channelUpdated(Channel channel, Optional newValue) { fieldValue = new NumberFieldValue(field, (Number) value); } else if (value instanceof String) { fieldValue = new StringFieldValue(field, (String) value); + }else if (value instanceof ChannelEnum) { + fieldValue = new NumberFieldValue(field, ((ChannelEnum)value).getValue()); } else { return; } @@ -212,4 +222,9 @@ public JsonArray queryHistoricData(Optional deviceIdOpt, ZonedDateTime protected int getCycleTime() { return cycleTime.valueOptional().orElse(DEFAULT_CYCLETIME); } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } } \ No newline at end of file diff --git a/edge/src/io/openems/impl/protocol/modbus/FaultModbus.java b/edge/src/io/openems/impl/protocol/modbus/FaultModbus.java new file mode 100644 index 00000000000..71624781ade --- /dev/null +++ b/edge/src/io/openems/impl/protocol/modbus/FaultModbus.java @@ -0,0 +1,19 @@ +package io.openems.impl.protocol.modbus; + +import io.openems.api.channel.thingstate.FaultEnum; + +public enum FaultModbus implements FaultEnum { + ConfigurationFault(0), + ConnectionFault(1); + + private final int value; + + private FaultModbus(int value) { + this.value = value; + } + + @Override + public int getValue() { + return this.value; + } +} diff --git a/edge/src/io/openems/impl/protocol/modbus/ModbusBitWrappingChannel.java b/edge/src/io/openems/impl/protocol/modbus/ModbusBitWrappingChannel.java new file mode 100644 index 00000000000..e973cd6e74a --- /dev/null +++ b/edge/src/io/openems/impl/protocol/modbus/ModbusBitWrappingChannel.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * OpenEMS - Open Source Energy Management System + * Copyright (c) 2016, 2017 FENECON GmbH and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contributors: + * FENECON GmbH - initial API and implementation and initial documentation + *******************************************************************************/ +package io.openems.impl.protocol.modbus; + +import io.openems.api.channel.BitToBooleanThingStateChannel; +import io.openems.api.channel.thingstate.FaultEnum; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.channel.thingstate.WarningEnum; +import io.openems.api.device.nature.DeviceNature; +import io.openems.api.exception.ConfigException; + +public class ModbusBitWrappingChannel extends ModbusReadChannel { + + private final ThingStateChannels thingState; + + public ModbusBitWrappingChannel(String id, DeviceNature nature, ThingStateChannels thingStateChannel) { + super(id, nature); + this.thingState = thingStateChannel; + } + + public ModbusBitWrappingChannel warningBit(int bitIndex, WarningEnum warningCode) throws ConfigException { + thingState.addWarningChannel(new BitToBooleanThingStateChannel(warningCode, this.parent(), this, bitIndex)); + return this; + } + + public ModbusBitWrappingChannel faultBit(int bitIndex, FaultEnum faultCode) throws ConfigException { + thingState.addFaultChannel(new BitToBooleanThingStateChannel(faultCode, this.parent(), this, bitIndex)); + return this; + } + +} diff --git a/edge/src/io/openems/impl/protocol/modbus/ModbusBridge.java b/edge/src/io/openems/impl/protocol/modbus/ModbusBridge.java index 2709c6b9e7d..8f4782954dd 100644 --- a/edge/src/io/openems/impl/protocol/modbus/ModbusBridge.java +++ b/edge/src/io/openems/impl/protocol/modbus/ModbusBridge.java @@ -51,6 +51,10 @@ @ThingInfo(title = "Modbus") public abstract class ModbusBridge extends Bridge { + public ModbusBridge() { + super(); + } + /* * Abstract Methods */ diff --git a/edge/src/io/openems/impl/protocol/modbus/ModbusRtu.java b/edge/src/io/openems/impl/protocol/modbus/ModbusRtu.java index e5a445dad27..c88e15415bc 100644 --- a/edge/src/io/openems/impl/protocol/modbus/ModbusRtu.java +++ b/edge/src/io/openems/impl/protocol/modbus/ModbusRtu.java @@ -31,9 +31,11 @@ import io.openems.api.channel.Channel; import io.openems.api.channel.ChannelUpdateListener; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.StaticThingStateChannel; import io.openems.api.device.Device; import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.ConfigException; import io.openems.api.exception.OpenemsModbusException; @ThingInfo(title = "Modbus/RTU") @@ -51,28 +53,38 @@ public void channelUpdated(Channel channel, Optional newValue) { */ @ChannelInfo(title = "Baudrate", description = "Sets the baudrate (e.g. 9600).", type = Integer.class) public final ConfigChannel baudrate = new ConfigChannel("baudrate", this) - .addUpdateListener(channelUpdateListener); + .addUpdateListener(channelUpdateListener); @ChannelInfo(title = "Databits", description = "Sets the databits (e.g. 8).", type = Integer.class) public final ConfigChannel databits = new ConfigChannel("databits", this) - .addUpdateListener(channelUpdateListener); + .addUpdateListener(channelUpdateListener); @ChannelInfo(title = "Parity", description = "Sets the parity (e.g. 'even').", type = String.class) public final ConfigChannel parity = new ConfigChannel("parity", this) - .addUpdateListener(channelUpdateListener); + .addUpdateListener(channelUpdateListener); @ChannelInfo(title = "Serial interface", description = "Sets the serial interface (e.g. /dev/ttyUSB0).", type = String.class) public final ConfigChannel serialinterface = new ConfigChannel("serialinterface", this) - .addUpdateListener(channelUpdateListener); + .addUpdateListener(channelUpdateListener); @ChannelInfo(title = "Stopbits", description = "Sets the stopbits (e.g. 1).", type = Integer.class) public final ConfigChannel stopbits = new ConfigChannel("stopbits", this) - .addUpdateListener(channelUpdateListener); + .addUpdateListener(channelUpdateListener); /* * Fields */ private Optional connection = Optional.empty(); + private StaticThingStateChannel configurationFault; + private StaticThingStateChannel connectionFault; + + public ModbusRtu() throws ConfigException { + super(); + this.configurationFault = new StaticThingStateChannel(FaultModbus.ConfigurationFault, this, false); + super.thingState.addFaultChannel(this.configurationFault); + this.connectionFault = new StaticThingStateChannel(FaultModbus.ConnectionFault, this, false); + super.thingState.addFaultChannel(this.connectionFault); + } /* * Methods @@ -141,12 +153,14 @@ private SerialConnection getModbusConnection() throws OpenemsModbusException { params.setEncoding(Modbus.SERIAL_ENCODING_RTU); params.setEcho(false); connection = Optional.of(new SerialConnection(params)); + this.configurationFault.setValue(false); } if (!connection.get().isOpen()) { try { SerialConnection serialCon = connection.get(); serialCon.open(); serialCon.getModbusTransport().setTimeout(1000); + this.connectionFault.setValue(false); } catch (Exception e) { throw new OpenemsModbusException("Unable to open Modbus-RTU connection: " + connection); } diff --git a/edge/src/io/openems/impl/protocol/modbus/ModbusTcp.java b/edge/src/io/openems/impl/protocol/modbus/ModbusTcp.java index fe13704a32d..65d8b984da0 100644 --- a/edge/src/io/openems/impl/protocol/modbus/ModbusTcp.java +++ b/edge/src/io/openems/impl/protocol/modbus/ModbusTcp.java @@ -33,9 +33,11 @@ import io.openems.api.channel.Channel; import io.openems.api.channel.ChannelUpdateListener; import io.openems.api.channel.ConfigChannel; +import io.openems.api.channel.StaticThingStateChannel; import io.openems.api.device.Device; import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; +import io.openems.api.exception.ConfigException; import io.openems.api.exception.InvalidValueException; import io.openems.api.exception.OpenemsModbusException; @@ -54,11 +56,11 @@ public void channelUpdated(Channel channel, Optional newValue) { */ @ChannelInfo(title = "IP address", description = "Sets the IP address (e.g. 10.0.0.15).", type = Inet4Address.class) public final ConfigChannel ip = new ConfigChannel("ip", this) - .addUpdateListener(channelUpdateListener); + .addUpdateListener(channelUpdateListener); @ChannelInfo(title = "Port", description = "Sets the port (e.g. 502).", type = Integer.class, defaultValue = "502") public final ConfigChannel port = new ConfigChannel("port", this) - .addUpdateListener(channelUpdateListener); + .addUpdateListener(channelUpdateListener); /* * Fields @@ -66,6 +68,16 @@ public void channelUpdated(Channel channel, Optional newValue) { private static Logger log = LoggerFactory.getLogger(ModbusTcp.class); private Optional connection = Optional.empty(); + private StaticThingStateChannel configurationFault; + private StaticThingStateChannel connectionFault; + + public ModbusTcp() throws ConfigException { + super(); + this.configurationFault = new StaticThingStateChannel(FaultModbus.ConfigurationFault, this, false); + super.thingState.addFaultChannel(this.configurationFault); + this.connectionFault = new StaticThingStateChannel(FaultModbus.ConnectionFault, this, false); + super.thingState.addFaultChannel(this.connectionFault); + } /* * Methods @@ -124,7 +136,9 @@ private TCPMasterConnection getModbusConnection() throws OpenemsModbusException TCPMasterConnection tcpCon = new TCPMasterConnection(ip.value()); tcpCon.setPort(port.valueOptional().orElse(502)); connection = Optional.of(tcpCon); + this.configurationFault.setValue(false); } catch (InvalidValueException e) { + this.configurationFault.setValue(true); throw new OpenemsModbusException("Modbus-TCP is not configured completely"); } } @@ -133,7 +147,9 @@ private TCPMasterConnection getModbusConnection() throws OpenemsModbusException TCPMasterConnection tcpCon = connection.get(); tcpCon.connect(); tcpCon.getModbusTransport().setTimeout(1000); + this.connectionFault.setValue(false); } catch (Exception e) { + this.connectionFault.setValue(true); throw new OpenemsModbusException("Unable to open Modbus-TCP connection: " + ip.valueOptional().get()); } } diff --git a/edge/src/io/openems/impl/scheduler/SimpleScheduler.java b/edge/src/io/openems/impl/scheduler/SimpleScheduler.java index c7d7c333bd0..8b9d1c00c02 100644 --- a/edge/src/io/openems/impl/scheduler/SimpleScheduler.java +++ b/edge/src/io/openems/impl/scheduler/SimpleScheduler.java @@ -27,6 +27,7 @@ import info.faljse.SDNotify.SDNotify; import io.openems.api.bridge.Bridge; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.doc.ThingInfo; import io.openems.api.scheduler.Scheduler; @@ -34,11 +35,13 @@ @ThingInfo(title = "App-Planner") public class SimpleScheduler extends Scheduler { + private ThingStateChannels thingState; + /* * Constructors */ public SimpleScheduler() { - + this.thingState = new ThingStateChannels(this); } /* @@ -71,4 +74,9 @@ protected boolean initialize() { return true; } + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } + } diff --git a/edge/src/io/openems/impl/scheduler/channelthreshold/ChannelThresholdScheduler.java b/edge/src/io/openems/impl/scheduler/channelthreshold/ChannelThresholdScheduler.java index 9c882c093f2..e6ef08130c6 100644 --- a/edge/src/io/openems/impl/scheduler/channelthreshold/ChannelThresholdScheduler.java +++ b/edge/src/io/openems/impl/scheduler/channelthreshold/ChannelThresholdScheduler.java @@ -35,6 +35,7 @@ import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.ReadChannel; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; @@ -47,8 +48,11 @@ @ThingInfo(title = "Channel threshold app-planer", description = "app-planer with thresholds on configured channel to run different controllers by threshold on channel.") public class ChannelThresholdScheduler extends Scheduler { + private ThingStateChannels thingState; + public ChannelThresholdScheduler() { thingRepository = ThingRepository.getInstance(); + this.thingState = new ThingStateChannels(this); } /* @@ -296,4 +300,9 @@ public boolean isBetween(long value) { return min <= value && value <= max; } } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } } diff --git a/edge/src/io/openems/impl/scheduler/time/WeekTimeScheduler.java b/edge/src/io/openems/impl/scheduler/time/WeekTimeScheduler.java index 1dfa15bfb56..761e9fedc44 100644 --- a/edge/src/io/openems/impl/scheduler/time/WeekTimeScheduler.java +++ b/edge/src/io/openems/impl/scheduler/time/WeekTimeScheduler.java @@ -37,6 +37,7 @@ import io.openems.api.bridge.Bridge; import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.controller.Controller; import io.openems.api.doc.ChannelInfo; import io.openems.api.doc.ThingInfo; @@ -50,11 +51,14 @@ @ThingInfo(title = "Weekly App-Planner", description = "Define recurring weekly plans.") public class WeekTimeScheduler extends Scheduler { + private ThingStateChannels thingState; + /* * Constructors */ public WeekTimeScheduler() { thingRepository = ThingRepository.getInstance(); + this.thingState = new ThingStateChannels(this); } /* @@ -219,4 +223,9 @@ public synchronized void removeController(Controller controller) { // remove controller from all times super.removeController(controller); } + + @Override + public ThingStateChannels getStateChannel() { + return this.thingState; + } } diff --git a/edge/src/io/openems/test/controller/ThermalPowerStationTest.java b/edge/src/io/openems/test/controller/ThermalPowerStationTest.java index b60f8ae097c..106b3079b18 100644 --- a/edge/src/io/openems/test/controller/ThermalPowerStationTest.java +++ b/edge/src/io/openems/test/controller/ThermalPowerStationTest.java @@ -1,133 +1,140 @@ -package io.openems.test.controller; - -import static org.junit.Assert.assertEquals; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import io.openems.api.thing.Thing; -import io.openems.impl.controller.thermalpowerstation.Ess; -import io.openems.impl.controller.thermalpowerstation.Meter; -import io.openems.impl.controller.thermalpowerstation.ThermalPowerStationController; -import io.openems.test.utils.channel.UnitTestWriteChannel; -import io.openems.test.utils.devicenatures.UnitTestAsymmetricEssNature; -import io.openems.test.utils.devicenatures.UnitTestSymmetricMeterNature; - -public class ThermalPowerStationTest { - - private static ThermalPowerStationController controller; - private static UnitTestAsymmetricEssNature ess; - private static UnitTestWriteChannel outputChannel; - private static UnitTestSymmetricMeterNature meter; - private static Ess essThingMap; - private static Meter meterThingMap; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - ess = new UnitTestAsymmetricEssNature("ess0"); - meter = new UnitTestSymmetricMeterNature("meter0"); - controller = new ThermalPowerStationController(); - outputChannel = new UnitTestWriteChannel<>("0", new Thing() { - - @Override - public String id() { - return "output0"; - } - }); - essThingMap = new Ess(ess); - meterThingMap = new Meter(meter); - controller.ess.updateValue(essThingMap, true); - List meters = new ArrayList<>(); - meters.add(meterThingMap); - controller.meters.updateValue(meters, true); - controller.outputChannelOpt = Optional.of(outputChannel); - controller.productionLimit.updateValue(1000L, true); - controller.limitTimeRange.updateValue(1L, true); - controller.minSoc.updateValue(15L, true); - controller.maxSoc.updateValue(95L, true); - controller.invertOutput.updateValue(false, true); - } - - @Before - public void beforeTest() { - outputChannel.shadowCopyAndReset(); - } - - @Test - public void test1() { - ess.soc.setValue(15L); - meter.activePower.setValue(0L); - outputChannel.setValue(false); - controller.run(); - assertEquals(false, outputChannel.getWriteValue().isPresent()); - } - - @Test - public void test2() { - ess.soc.setValue(15L); - meter.activePower.setValue(0L); - outputChannel.setValue(true); - outputChannel.shadowCopyAndReset(); - // OFF - controller.run(); - assertEquals(false, outputChannel.getWriteValue().isPresent()); - outputChannel.shadowCopyAndReset(); - // SWITCH OFF - controller.run(); - assertEquals(true, outputChannel.getWriteValue().isPresent()); - boolean output = outputChannel.getWriteValue().get(); - assertEquals(false, output); - outputChannel.setValue(false); - outputChannel.shadowCopyAndReset(); - // SWITCH OFF - controller.run(); - assertEquals(false, outputChannel.getWriteValue().isPresent()); - outputChannel.shadowCopyAndReset(); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - // OFF - controller.run(); - assertEquals(false, outputChannel.getWriteValue().isPresent()); - outputChannel.shadowCopyAndReset(); - // SWITCH ON - controller.run(); - assertEquals(true, outputChannel.getWriteValue().isPresent()); - output = outputChannel.getWriteValue().get(); - assertEquals(true, output); - } - - @Test - public void test3() { - ess.soc.setValue(15L); - meter.activePower.setValue(5000L); - outputChannel.setValue(true); - outputChannel.shadowCopyAndReset(); - // OFF - controller.run(); - assertEquals(false, outputChannel.getWriteValue().isPresent()); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - controller.run(); - outputChannel.shadowCopyAndReset(); - assertEquals(false, outputChannel.getWriteValue().isPresent()); - outputChannel.shadowCopyAndReset(); - controller.run(); - assertEquals(true, outputChannel.getWriteValue().isPresent()); - boolean output = outputChannel.getWriteValue().get(); - assertEquals(false, output); - } - -} +package io.openems.test.controller; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.thing.Thing; +import io.openems.impl.controller.thermalpowerstation.Ess; +import io.openems.impl.controller.thermalpowerstation.Meter; +import io.openems.impl.controller.thermalpowerstation.ThermalPowerStationController; +import io.openems.test.utils.channel.UnitTestWriteChannel; +import io.openems.test.utils.devicenatures.UnitTestAsymmetricEssNature; +import io.openems.test.utils.devicenatures.UnitTestSymmetricMeterNature; + +public class ThermalPowerStationTest { + + private static ThermalPowerStationController controller; + private static UnitTestAsymmetricEssNature ess; + private static UnitTestWriteChannel outputChannel; + private static UnitTestSymmetricMeterNature meter; + private static Ess essThingMap; + private static Meter meterThingMap; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + ess = new UnitTestAsymmetricEssNature("ess0"); + meter = new UnitTestSymmetricMeterNature("meter0"); + controller = new ThermalPowerStationController(); + outputChannel = new UnitTestWriteChannel<>("0", new Thing() { + + @Override + public String id() { + return "output0"; + } + + @Override + public ThingStateChannels getStateChannel() { + // TODO Auto-generated method stub + return null; + } + }); + essThingMap = new Ess(ess); + meterThingMap = new Meter(meter); + controller.ess.updateValue(essThingMap, true); + List meters = new ArrayList<>(); + meters.add(meterThingMap); + controller.meters.updateValue(meters, true); + controller.outputChannelOpt = Optional.of(outputChannel); + controller.productionLimit.updateValue(1000L, true); + controller.limitTimeRange.updateValue(1L, true); + controller.minSoc.updateValue(15L, true); + controller.maxSoc.updateValue(95L, true); + controller.invertOutput.updateValue(false, true); + } + + @Before + public void beforeTest() { + outputChannel.shadowCopyAndReset(); + } + + @Test + public void test1() { + ess.soc.setValue(15L); + meter.activePower.setValue(0L); + outputChannel.setValue(false); + controller.run(); + assertEquals(false, outputChannel.getWriteValue().isPresent()); + } + + @Test + public void test2() { + ess.soc.setValue(15L); + meter.activePower.setValue(0L); + outputChannel.setValue(true); + outputChannel.shadowCopyAndReset(); + // OFF + controller.run(); + assertEquals(false, outputChannel.getWriteValue().isPresent()); + outputChannel.shadowCopyAndReset(); + // SWITCH OFF + controller.run(); + assertEquals(true, outputChannel.getWriteValue().isPresent()); + boolean output = outputChannel.getWriteValue().get(); + assertEquals(false, output); + outputChannel.setValue(false); + outputChannel.shadowCopyAndReset(); + // SWITCH OFF + controller.run(); + assertEquals(false, outputChannel.getWriteValue().isPresent()); + outputChannel.shadowCopyAndReset(); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // OFF + controller.run(); + assertEquals(false, outputChannel.getWriteValue().isPresent()); + outputChannel.shadowCopyAndReset(); + // SWITCH ON + controller.run(); + assertEquals(true, outputChannel.getWriteValue().isPresent()); + output = outputChannel.getWriteValue().get(); + assertEquals(true, output); + } + + @Test + public void test3() { + ess.soc.setValue(15L); + meter.activePower.setValue(5000L); + outputChannel.setValue(true); + outputChannel.shadowCopyAndReset(); + // OFF + controller.run(); + assertEquals(false, outputChannel.getWriteValue().isPresent()); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + controller.run(); + outputChannel.shadowCopyAndReset(); + assertEquals(false, outputChannel.getWriteValue().isPresent()); + outputChannel.shadowCopyAndReset(); + controller.run(); + assertEquals(true, outputChannel.getWriteValue().isPresent()); + boolean output = outputChannel.getWriteValue().get(); + assertEquals(false, output); + } + +} diff --git a/edge/src/io/openems/test/utils/channel/UnitTestReadChannel.java b/edge/src/io/openems/test/utils/channel/UnitTestReadChannel.java index 3f404e64e53..0a5c4572a01 100644 --- a/edge/src/io/openems/test/utils/channel/UnitTestReadChannel.java +++ b/edge/src/io/openems/test/utils/channel/UnitTestReadChannel.java @@ -1,31 +1,38 @@ -package io.openems.test.utils.channel; - -import io.openems.api.thing.Thing; - -public class UnitTestReadChannel extends io.openems.api.channel.ReadChannel { - - public UnitTestReadChannel(String deviceName,String id){ - super(id,new Thing() { - - @Override - public String id() { - return deviceName; - } - }); - } - - public UnitTestReadChannel(String id, Thing parent) { - super(id, parent); - } - - public void setValue(T value) { - this.updateValue(value); - } - - @Override - public UnitTestReadChannel label(T value, String label) { - super.label(value, label); - return this; - } - -} +package io.openems.test.utils.channel; + +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.thing.Thing; + +public class UnitTestReadChannel extends io.openems.api.channel.ReadChannel { + + public UnitTestReadChannel(String deviceName,String id){ + super(id,new Thing() { + + @Override + public String id() { + return deviceName; + } + + @Override + public ThingStateChannels getStateChannel() { + // TODO Auto-generated method stub + return null; + } + }); + } + + public UnitTestReadChannel(String id, Thing parent) { + super(id, parent); + } + + public void setValue(T value) { + this.updateValue(value); + } + + @Override + public UnitTestReadChannel label(T value, String label) { + super.label(value, label); + return this; + } + +} diff --git a/edge/src/io/openems/test/utils/channel/UnitTestWriteChannel.java b/edge/src/io/openems/test/utils/channel/UnitTestWriteChannel.java index c7f2baaebfb..9ee51e41a61 100644 --- a/edge/src/io/openems/test/utils/channel/UnitTestWriteChannel.java +++ b/edge/src/io/openems/test/utils/channel/UnitTestWriteChannel.java @@ -1,43 +1,50 @@ -package io.openems.test.utils.channel; - -import java.util.Optional; - -import io.openems.api.channel.ReadChannel; -import io.openems.api.channel.WriteChannel; -import io.openems.api.thing.Thing; - -public class UnitTestWriteChannel extends WriteChannel { - - public UnitTestWriteChannel(String deviceName, String id) { - super(id, new Thing() { - - @Override - public String id() { - return id; - } - }); - } - - public UnitTestWriteChannel(String id, Thing parent) { - super(id, parent); - } - - public void setValue(T value) { - this.updateValue(value); - } - - public Optional getWrittenValue() { - return writeShadowCopy; - } - - @Override - public UnitTestWriteChannel maxWriteChannel(ReadChannel channel) { - return (UnitTestWriteChannel) super.maxWriteChannel(channel); - } - - @Override - public UnitTestWriteChannel minWriteChannel(ReadChannel channel) { - return (UnitTestWriteChannel) super.minWriteChannel(channel); - } - -} +package io.openems.test.utils.channel; + +import java.util.Optional; + +import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; +import io.openems.api.thing.Thing; + +public class UnitTestWriteChannel extends WriteChannel { + + public UnitTestWriteChannel(String deviceName, String id) { + super(id, new Thing() { + + @Override + public String id() { + return id; + } + + @Override + public ThingStateChannels getStateChannel() { + // TODO Auto-generated method stub + return null; + } + }); + } + + public UnitTestWriteChannel(String id, Thing parent) { + super(id, parent); + } + + public void setValue(T value) { + this.updateValue(value); + } + + public Optional getWrittenValue() { + return writeShadowCopy; + } + + @Override + public UnitTestWriteChannel maxWriteChannel(ReadChannel channel) { + return (UnitTestWriteChannel) super.maxWriteChannel(channel); + } + + @Override + public UnitTestWriteChannel minWriteChannel(ReadChannel channel) { + return (UnitTestWriteChannel) super.minWriteChannel(channel); + } + +} diff --git a/edge/src/io/openems/test/utils/devicenatures/UnitTestAsymmetricEssNature.java b/edge/src/io/openems/test/utils/devicenatures/UnitTestAsymmetricEssNature.java index c41804a3e2b..8efc1f464fd 100644 --- a/edge/src/io/openems/test/utils/devicenatures/UnitTestAsymmetricEssNature.java +++ b/edge/src/io/openems/test/utils/devicenatures/UnitTestAsymmetricEssNature.java @@ -8,8 +8,8 @@ import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.ReadChannel; import io.openems.api.channel.StaticValueChannel; -import io.openems.api.channel.StatusBitChannels; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.ess.AsymmetricEssNature; import io.openems.impl.device.simulator.SimulatorTools; @@ -92,11 +92,6 @@ public ReadChannel allowedApparent() { return allowedApparent; } - @Override - public StatusBitChannels warning() { - return null; - } - @Override public WriteChannel setWorkState() { return setWorkState; @@ -206,4 +201,10 @@ public List getWriteTasks() { return null; } + @Override + public ThingStateChannels getStateChannel() { + // TODO Auto-generated method stub + return null; + } + } diff --git a/edge/src/io/openems/test/utils/devicenatures/UnitTestAsymmetricMeterNature.java b/edge/src/io/openems/test/utils/devicenatures/UnitTestAsymmetricMeterNature.java index 5a9c3ac05c0..ffaa967a7bf 100644 --- a/edge/src/io/openems/test/utils/devicenatures/UnitTestAsymmetricMeterNature.java +++ b/edge/src/io/openems/test/utils/devicenatures/UnitTestAsymmetricMeterNature.java @@ -7,6 +7,7 @@ import io.openems.api.channel.Channel; import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.meter.AsymmetricMeterNature; import io.openems.test.utils.channel.UnitTestReadChannel; @@ -145,4 +146,10 @@ public List getWriteTasks() { return null; } + @Override + public ThingStateChannels getStateChannel() { + // TODO Auto-generated method stub + return null; + } + } diff --git a/edge/src/io/openems/test/utils/devicenatures/UnitTestSymmetricEssNature.java b/edge/src/io/openems/test/utils/devicenatures/UnitTestSymmetricEssNature.java index ec62384b11f..20c02d43764 100644 --- a/edge/src/io/openems/test/utils/devicenatures/UnitTestSymmetricEssNature.java +++ b/edge/src/io/openems/test/utils/devicenatures/UnitTestSymmetricEssNature.java @@ -8,8 +8,8 @@ import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.ReadChannel; import io.openems.api.channel.StaticValueChannel; -import io.openems.api.channel.StatusBitChannels; import io.openems.api.channel.WriteChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.ess.EssNature; import io.openems.api.device.nature.ess.SymmetricEssNature; @@ -84,11 +84,6 @@ public ReadChannel allowedApparent() { return allowedApparent; } - @Override - public StatusBitChannels warning() { - return null; - } - @Override public WriteChannel setWorkState() { return setWorkState; @@ -163,4 +158,10 @@ public List getWriteTasks() { return null; } + @Override + public ThingStateChannels getStateChannel() { + // TODO Auto-generated method stub + return null; + } + } diff --git a/edge/src/io/openems/test/utils/devicenatures/UnitTestSymmetricMeterNature.java b/edge/src/io/openems/test/utils/devicenatures/UnitTestSymmetricMeterNature.java index 17c4a535f01..da69153a36b 100644 --- a/edge/src/io/openems/test/utils/devicenatures/UnitTestSymmetricMeterNature.java +++ b/edge/src/io/openems/test/utils/devicenatures/UnitTestSymmetricMeterNature.java @@ -7,6 +7,7 @@ import io.openems.api.channel.Channel; import io.openems.api.channel.ConfigChannel; import io.openems.api.channel.ReadChannel; +import io.openems.api.channel.thingstate.ThingStateChannels; import io.openems.api.device.Device; import io.openems.api.device.nature.meter.SymmetricMeterNature; import io.openems.test.utils.channel.UnitTestReadChannel; @@ -101,4 +102,10 @@ public List getWriteTasks() { return null; } + @Override + public ThingStateChannels getStateChannel() { + // TODO Auto-generated method stub + return null; + } + } diff --git a/edge/template/FeneconCommercialDC.json b/edge/template/FeneconCommercialDC.json deleted file mode 100644 index 093d6cb2c6d..00000000000 --- a/edge/template/FeneconCommercialDC.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "things": [ - { - "class": "io.openems.impl.protocol.modbus.ModbusTcp", - "ip": "10.4.0.15", - "cycleTime": 500, - "devices": [ - { - "id": "_device0", - "class": "io.openems.impl.device.commercial.FeneconCommercialDC", - "modbusUnitId": 100, - "ess": { - "id": "ess0", - "minSoc": 15, - "chargeSoc": 10 - }, - "charger": { - "id": "charger0" - } - } - ] - }, - { - "class": "io.openems.impl.protocol.modbus.ModbusRtu", - "databits": 8, - "serialinterface": "/dev/ttyUSB0", - "parity": "none", - "baudrate": 9600, - "stopbits": 1, - "cycleTime": 500, - "devices": [ - { - "id": "_device1", - "class": "io.openems.impl.device.socomec.Socomec", - "meter": { - "id": "meter0", - "type": "grid" - }, - "modbusUnitId": 5 - } - ] - } - ], - "scheduler": { - "class": "io.openems.impl.scheduler.SimpleScheduler", - "cycleTime": 500, - "controllers": [ - { - "class": "io.openems.impl.controller.symmetric.commercialworkstate.AlwaysOnController", - "priority": 0, - "esss": [ - "ess0" - ] - }, - { - "class": "io.openems.impl.controller.symmetric.avoidtotaldischarge.AvoidTotalDischargeController", - "priority": 100, - "esss": [ - "ess0" - ] - }, - { - "class": "io.openems.impl.controller.symmetric.balancing.BalancingController", - "esss": [ - "ess0" - ], - "meter": "meter0", - "priority": 50 - }, - { - "class": "io.openems.impl.controller.debuglog.DebugLogController", - "esss": [ - "ess0" - ], - "priority": 150, - "meters": [ - "meter0" - ] - } - ] - }, - "persistence": [ - { - "class": "io.openems.impl.persistence.influxdb.InfluxdbPersistence", - "ip": "127.0.0.1", - "fems": 0 - }, - { - "class": "io.openems.impl.persistence.fenecon.FeneconPersistence", - "apikey": "" - } - ] -} diff --git "a/edge/template/app/FEMS App SG-Ready W\303\244rmepumpe.json" "b/edge/template/app/FEMS App SG-Ready W\303\244rmepumpe.json" index 09c737b319e..52a33605fb7 100644 --- "a/edge/template/app/FEMS App SG-Ready W\303\244rmepumpe.json" +++ "b/edge/template/app/FEMS App SG-Ready W\303\244rmepumpe.json" @@ -1,19 +1,19 @@ -{ - "class": "io.openems.impl.controller.channelthreshold.ChannelThresholdController", - "priority": 60, - "thresholdChannelAddress": "ess0/Soc", - "outputChannelAddress": "output0/0", - "lowerThreshold": 40, - "upperThreshold": 45, - "hysteresis": 5 -}, -{ - "class": "io.openems.impl.controller.channelthreshold.ChannelThresholdController", - "priority": 65, - "thresholdChannelAddress": "ess0/Soc", - "outputChannelAddress": "output0/1", - "lowerThreshold": 75, - "upperThreshold": 80, - "invertOutput": true, - "hysteresis": 5 +{ + "class": "io.openems.impl.controller.channelthreshold.ChannelThresholdController", + "priority": 60, + "thresholdChannelAddress": "ess0/Soc", + "outputChannelAddress": "output0/0", + "lowerThreshold": 0, + "upperThreshold": 40, + "hysteresis": 5 +}, +{ + "class": "io.openems.impl.controller.channelthreshold.ChannelThresholdController", + "priority": 65, + "thresholdChannelAddress": "ess0/Soc", + "outputChannelAddress": "output0/1", + "lowerThreshold": 80, + "upperThreshold": 100, + "invertOutput": true, + "hysteresis": 5 } \ No newline at end of file diff --git a/setup/devices b/setup/devices new file mode 100644 index 00000000000..67aec8d47c3 --- /dev/null +++ b/setup/devices @@ -0,0 +1 @@ +#name;password;apikey;packages \ No newline at end of file diff --git a/setup/setup.sh b/setup/setup.sh new file mode 100644 index 00000000000..aa12150d0d0 --- /dev/null +++ b/setup/setup.sh @@ -0,0 +1,201 @@ +#!/bin/bash +# +# Script to automatically setup a FEMS. +# Setup parameters are taken from the first line of a devices file in the format: +# ;;; +# +set -e + +# Define status files +FINISHED_1=/opt/fems-setup/finished_1 +FINISHED_2=/opt/fems-setup/finished_2 +DEVICES=/opt/fems-setup/devices + +# First stage: Copy filesystem to internal eMMC +if [ ! -e $FINISHED_1 ]; then + echo "#" + echo "# Starting first stage of FEMS setup" + echo "#" + + if [ "$(cat /boot/uboot/fems-setup/devices | wc -l)" == "1" ]; then + echo "# No devices left in configuration file" + echo "#" + echo "# Aborting" + exit 1 + fi + +#selection process +CHOICE=$(whiptail --menu "Wähle aus:" 18 40 9 \ + "FENECON Mini" "" \ + "FENECON DESS" "" \ + "FENECON Pro" "" \ + "FENECON Pro AC-Insel" "" \ + "FENECON Pro Heizstab" "" \ + "FENECON Pro Wärmepumpe" "" \ + "FENECON Commercial AC" "" \ + "FENECON Commercial DC" "" \ + "FENECON Commercial Hybrid" "" 3>&1 1>&2 2>&3) + + if [ $? = 0 ]; then + + case $CHOICE in + "FENECON Mini") echo "Es wurde Mini gewählt";; + "FENECON DESS") echo "Es wurde Pro Hybrid gewählt";; + "FENECON Pro") echo "Es wurde Pro 9-12 gewählt";; + "FENECON Pro AC-Insel") echo "Es wurde AC-Insel gewählt";; + "FENECON Pro Heizstab") echo "Es wurde Heizstab gewählt";; + "FENECON Pro Waermepumpe") echo "Es wurde Wärmepumpe gewählt";; + "FENECON Commercial AC") echo "Es wurde Commercial AC gewählt";; + "FENECON Commercial DC") echo "Es wurde Commercial DC gewählt";; + "FENECON Commercial Hybrid") echo "Es wurde Comemrcial Hybrid gewählt";; + + esac + + else + echo "Nichts ausgewählt" + exit + fi + echo "#save variable to file" + touch /opt/choice && echo $CHOICE > /opt/choice + + echo "# Copy templates to target" + cp -r /boot/uboot/fems-setup/templates /opt/fems-setup/ + + echo "# Copy filesystem to internal eMMC" + cd /opt/scripts/tools/eMMC + ./bbb-eMMC-flasher-eewiki-ext4.sh || true + + echo "# Mount target filesystem" + /bin/mount /dev/mmcblk1p1 /mnt + + echo "# Copy setup script to target" + mkdir -p /mnt/opt/fems-setup + cp /boot/uboot/fems-setup/setup.sh /mnt/opt/fems-setup/ + + echo "# Copy current fems data to target" + /usr/bin/head -n 2 /boot/uboot/fems-setup/devices > /mnt/opt/fems-setup/devices + + echo "# Remove fems from devices list" + /bin/sed --expression='2d' /boot/uboot/fems-setup/devices --in-place + + echo "# Mark first stage as finished" + touch /mnt$FINISHED_1 + /bin/umount /mnt + + echo "# Blink all LEDs" + echo timer | tee /sys/class/leds/beaglebone:green:usr?/trigger >/dev/null + + read -p "Press [Enter] key to shutdown" + + echo "# Shutdown system" + shutdown -h now + +elif [ ! -e $FINISHED_2 ]; then + echo "#" + echo "# Starting second stage of FEMS setup" + echo "#" + + cd /opt/fems-setup + FEMS=$(head -n 2 devices | tail -n 1 | cut -d ";" -f 1) + PASSWORD=$(head -n 2 devices | tail -n 1 | cut -d ";" -f 2) + + + echo "# Set password for user fems" + echo "fems:${PASSWORD}" | /usr/sbin/chpasswd + + echo "# Set name to ${FEMS}" + echo $FEMS > /etc/hostname + /bin/sed "s/\(127.0.1.1.*\)fems.*/\1$FEMS/" /etc/hosts --in-place + echo $FEMS > /etc/mailname + rm -fv /etc/ssh/ssh_host_* + dpkg-reconfigure openssh-server + rm /etc/udev/rules.d/70-persistent-net.rules + + echo "# Blink all LEDs" + echo timer | tee /sys/class/leds/beaglebone:green:usr?/trigger >/dev/null + + echo "# Mark second stage as finished" + touch $FINISHED_2 + + read -p "Press [Enter] key to reboot" + echo "# Rebooting system" + reboot + +else + echo "#" + echo "# Starting third stage of FEMS setup" + echo "#" + + cd /opt/fems-setup + PACKAGES=$(head -n 2 devices | tail -n 1 | cut -d ";" -f 4) + + echo "# Add FENECON debian repository" + wget -O - http://fenecon.de/debian/fems.gpg.key | apt-key add - + wget http://fenecon.de/debian/fems.list -O /etc/apt/sources.list.d/fems.list + echo "# Add Debian Backports repository" + echo "deb http://ftp.de.debian.org/debian/ jessie-backports main contrib non-free" > /etc/apt/sources.list.d/jessie-backports.list + echo "# Refresh apt cache" + /usr/bin/aptitude update + echo "# Install openjdk 8" + /usr/bin/apt install -t jessie-backports openjdk-8-jre-headless -y + + CHOICE=$(cat /opt/choice) + + if [ "$CHOICE" == "FENECON DESS" ]; then + + aptitude install fems-dess fems-fenecononlinemonitoring --assume-yes + + else + aptitude install openems openems-fems openems-ui influxdb grafana + + # copy config and set name + apikey + CHOICE=$(cat /opt/choice) + mkdir -p /opt/config.d + + echo "# Write Apikey into /etc/fems" + APIKEY=$(head -n 2 /opt/fems-setup/devices | tail -n 1 | cut -d ";" -f 3) + echo "apikey=${APIKEY}" > /etc/fems + + cp "/opt/fems-setup/templates/$CHOICE.json" "/opt/config.d/$CHOICE.json" + NAME=$(head -n 2 /opt/fems-setup/devices | tail -n 1 | cut -d ";" -f 1) + + sed "s/\"###FEMS_ID###\"/${NAME:4}/" --in-place "/opt/config.d/$CHOICE.json" + + APIKEY=$(head -n 2 /opt/fems-setup/devices | tail -n 1 | cut -d ";" -f 3) + sed "s/###APIKEY###/$APIKEY/" --in-place "/opt/config.d/$CHOICE.json" + + CHOICE=$(cat /opt/choice) + mv "/opt/config.d/$CHOICE.json" "/etc/openems.d/config.json" + unlink /opt/choice + + fi + + # this is not working... + #echo "# preset apikey for dpkg-configure" + #. /usr/share/debconf/confmodule + #db_set fems-openhab-addon-fems/apikey $APIKEY + + # TODO remove setup-script from /opt/fems-setup + + if [ "${PACKAGES}" != "" ]; then + echo "# Install packages: ${PACKAGES}" + /usr/bin/aptitude install --assume-yes $PACKAGES -y + + else + echo "# Install NO packages!" + fi + + #echo "# Finialize setup with fems-autoupdate fems" + #/usr/bin/fems-autoupdate fems + + echo "#" + echo "# Finished setup" + echo "#" + + + fems-autoupdate fems -y || true + echo "# Blink all LEDs" + echo timer | tee /sys/class/leds/beaglebone:green:usr?/trigger >/dev/null + echo "# Rebooting system" + reboot +fi diff --git a/edge/template/FeneconCommercialAC.json b/setup/templates/FENECON Commercial AC.json similarity index 78% rename from edge/template/FeneconCommercialAC.json rename to setup/templates/FENECON Commercial AC.json index 2cd32f2fd04..3fbeadf5560 100644 --- a/edge/template/FeneconCommercialAC.json +++ b/setup/templates/FENECON Commercial AC.json @@ -1,76 +1,83 @@ -{ - "things": [ - { - "class": "io.openems.impl.protocol.modbus.ModbusTcp", - "ip": "10.4.0.15", - "devices": [ - { - "class": "io.openems.impl.device.commercial.FeneconCommercialAC", - "modbusUnitId": 100, - "ess": { - "id": "ess0", - "minSoc": 15, - "chargeSoc": 10 - } - } - ] - }, - { - "class": "io.openems.impl.protocol.modbus.ModbusRtu", - "serialinterface": "/dev/ttyUSB0", - "baudrate": 9600, - "databits": 8, - "parity": "none", - "stopbits": 1, - "devices": [ - { - "class": "io.openems.impl.device.socomec.Socomec", - "modbusUnitId": 5, - "meter": { - "id": "meter0" - } - } - ] - } - ], - "scheduler": { - "class": "io.openems.impl.scheduler.SimpleScheduler", - "controllers": [ - { - "priority": 150, - "class": "io.openems.impl.controller.debuglog.DebugLogController", - "esss": "ess0", - "meters": "meter0" - }, - { - "priority": 100, - "class": "io.openems.impl.controller.symmetric.avoidtotaldischarge.AvoidTotalDischargeController", - "esss": "ess0" - }, - { - "priority": 50, - "class": "io.openems.impl.controller.symmetric.balancing.BalancingController", - "esss": "ess0", - "meter": "meter0" - }, - { - "class": "io.openems.impl.controller.symmetric.commercialworkstate.AlwaysOnController", - "priority": 0, - "esss": [ - "ess0" - ] - } - ] - }, - "persistence": [ - { - "class": "io.openems.impl.persistence.influxdb.InfluxdbPersistence", - "ip": "127.0.0.1", - "fems": 0 - }, - { - "class": "io.openems.impl.persistence.fenecon.FeneconPersistence", - "apikey": "XXX" - } - ] -} +{ + "things": [ + { + "class": "io.openems.impl.protocol.modbus.ModbusTcp", + "ip": "10.4.0.15", + "devices": [ + { + "class": "io.openems.impl.device.commercial.FeneconCommercialAC", + "modbusUnitId": 100, + "ess": { + "id": "ess0", + "minSoc": 15, + "chargeSoc": 10 + } + } + ] + }, + { + "class": "io.openems.impl.protocol.modbus.ModbusRtu", + "serialinterface": "/dev/ttyUSB0", + "baudrate": 9600, + "databits": 8, + "parity": "none", + "stopbits": 1, + "devices": [ + { + "class": "io.openems.impl.device.socomec.Socomec", + "modbusUnitId": 5, + "meter": { + "id": "meter0", + "type": "grid" + } + }, + { + "class": "io.openems.impl.device.socomec.Socomec", + "modbusUnitId": 6, + "meter": { + "id": "meter1", + "type": "production" + } + } + ] + } + ], + "scheduler": { + "class": "io.openems.impl.scheduler.SimpleScheduler", + "controllers": [ + { + "priority": 150, + "class": "io.openems.impl.controller.debuglog.DebugLogController", + "esss": "ess0", + "meters": "meter0" + }, + { + "priority": 100, + "class": "io.openems.impl.controller.symmetric.avoidtotaldischarge.AvoidTotalDischargeController", + "esss": "ess0" + }, + { + "priority": 50, + "class": "io.openems.impl.controller.symmetric.balancing.BalancingController", + "esss": "ess0", + "meter": "meter0" + }, + { + "priority": 0, + "class": "io.openems.impl.controller.symmetric.commercialenergysaver.EnergysavingController", + "esss": "ess0" + } + ] + }, + "persistence": [ + { + "class": "io.openems.impl.persistence.influxdb.InfluxdbPersistence", + "ip": "127.0.0.1", + "fems": "###FEMS_ID###" + }, + { + "class": "io.openems.impl.persistence.fenecon.FeneconPersistence", + "apikey": "###APIKEY###" + } + ] +} \ No newline at end of file diff --git a/setup/templates/FENECON Commercial DC.json b/setup/templates/FENECON Commercial DC.json new file mode 100644 index 00000000000..41416fcbc27 --- /dev/null +++ b/setup/templates/FENECON Commercial DC.json @@ -0,0 +1,93 @@ +{ + "things": [ + { + "class": "io.openems.impl.protocol.modbus.ModbusTcp", + "ip": "10.4.0.15", + "cycleTime": 500, + "devices": [ + { + "id": "_device0", + "class": "io.openems.impl.device.commercial.FeneconCommercialDC", + "modbusUnitId": 100, + "ess": { + "id": "ess0", + "minSoc": 15, + "chargeSoc": 10 + }, + "charger": { + "id": "charger0" + } + } + ] + }, + { + "class": "io.openems.impl.protocol.modbus.ModbusRtu", + "databits": 8, + "serialinterface": "/dev/ttyUSB0", + "parity": "none", + "baudrate": 9600, + "stopbits": 1, + "cycleTime": 500, + "devices": [ + { + "id": "_device1", + "class": "io.openems.impl.device.socomec.Socomec", + "meter": { + "id": "meter0", + "type": "grid" + }, + "modbusUnitId": 5 + } + ] + } + ], + "scheduler": { + "class": "io.openems.impl.scheduler.SimpleScheduler", + "cycleTime": 500, + "controllers": [ + { + "class": "io.openems.impl.controller.symmetric.commercialworkstate.AlwaysOnController", + "priority": 0, + "esss": [ + "ess0" + ] + }, + { + "class": "io.openems.impl.controller.symmetric.avoidtotaldischarge.AvoidTotalDischargeController", + "priority": 100, + "esss": [ + "ess0" + ] + }, + { + "class": "io.openems.impl.controller.symmetric.balancing.BalancingController", + "esss": [ + "ess0" + ], + "meter": "meter0", + "priority": 50 + }, + { + "class": "io.openems.impl.controller.debuglog.DebugLogController", + "esss": [ + "ess0" + ], + "priority": 150, + "meters": [ + "meter0" + ] + } + ] + }, + "persistence": [ + { + "class": "io.openems.impl.persistence.influxdb.InfluxdbPersistence", + "ip": "127.0.0.1", + "fems": "###FEMS_ID###" + }, + { + "class": "io.openems.impl.persistence.fenecon.FeneconPersistence", + "apikey": "###APIKEY###" + } + ] +} \ No newline at end of file diff --git a/setup/templates/FENECON Commercial Hybrid.json b/setup/templates/FENECON Commercial Hybrid.json new file mode 100644 index 00000000000..993beb25323 --- /dev/null +++ b/setup/templates/FENECON Commercial Hybrid.json @@ -0,0 +1,103 @@ +{ + "things": [ + { + "class": "io.openems.impl.protocol.modbus.ModbusTcp", + "ip": "10.4.0.15", + "port": 502, + "devices": [ + { + "class": "io.openems.impl.device.commercial.FeneconCommercialDC", + "ess": { + "id": "ess0", + "minSoc": 15, + "chargeSoc": 10 + }, + "charger": { + "id": "charger0" + }, + "modbusUnitId": 100 + } + ] + }, + { + "class": "io.openems.impl.protocol.modbus.ModbusRtu", + "serialinterface": "/dev/ttyUSB0", + "baudrate": 9600, + "databits": 8, + "parity": "none", + "stopbits": 1, + "devices": [ + { + "class": "io.openems.impl.device.socomec.Socomec", + "modbusUnitId": 5, + "meter": { + "id": "meter0", + "type": "grid" + } + } + ] + } + ], + "scheduler": { + "class": "io.openems.impl.scheduler.SimpleScheduler", + "controllers": [ + { + "class": "io.openems.impl.controller.symmetric.commercialworkstate.AlwaysOnController", + "priority": 0, + "esss": [ + "ess0" + ] + }, + { + "class": "io.openems.impl.controller.symmetric.avoidtotaldischarge.AvoidTotalDischargeController", + "priority": 100, + "esss": [ + "ess0" + ], + "maxSoc": 95 + }, + { + "class": "io.openems.impl.controller.symmetric.balancingsurplus.BalancingSurplusController", + "meter": "meter0", + "ess": "ess0", + "priority": 50, + "surplusMinSoc": 85, + "chargers": [ + "charger0" + ] + }, + { + "class": "io.openems.impl.controller.debuglog.DebugLogController", + "priority": 151, + "esss": [ + "ess0" + ], + "meters": [ + "meter0", + "meter1" + ] + }, + { + "class": "io.openems.impl.controller.api.websocket.WebsocketApiController", + "port": 8085, + "priority": -2147483648 + }, + { + "class": "io.openems.impl.controller.api.rest.RestApiController", + "priority": -2147483648, + "port": 8084 + } + ] + }, + "persistence": [ + { + "class": "io.openems.impl.persistence.influxdb.InfluxdbPersistence", + "ip": "127.0.0.1", + "fems": "###FEMS_ID###" + }, + { + "class": "io.openems.impl.persistence.fenecon.FeneconPersistence", + "apikey": "###APIKEY###" + } + ] +} \ No newline at end of file diff --git a/setup/templates/FENECON Mini.json b/setup/templates/FENECON Mini.json new file mode 100644 index 00000000000..61ddfa0694a --- /dev/null +++ b/setup/templates/FENECON Mini.json @@ -0,0 +1,61 @@ +{ + "things": [ + { + "class": "io.openems.impl.protocol.modbus.ModbusRtu", + "serialinterface": "/dev/ttyUSB0", + "baudrate": 9600, + "databits": 8, + "parity": "none", + "stopbits": 1, + "devices": [ + { + "class": "io.openems.impl.device.minireadonly.FeneconMini", + "modbusUnitId": 4, + "ess": { + "id": "ess0", + "minSoc": 15 + }, + "gridMeter": { + "id": "meter0" + }, + "productionMeter": { + "id": "meter1" + }, + "consumptionMeter": { + "id": "meter2" + } + } + ] + } + ], + "scheduler": { + "class": "io.openems.impl.scheduler.SimpleScheduler", + "cycleTime": 10000, + "controllers": [ + { + "priority": 150, + "class": "io.openems.impl.controller.debuglog.DebugLogController", + "esss": [ + "ess0" + ], + "meters": [ + "meter0", + "meter1", + "meter2" + ] + } + ] + }, + "persistence": [ + { + "class": "io.openems.impl.persistence.influxdb.InfluxdbPersistence", + "ip": "127.0.0.1", + "fems": "###FEMS_ID###" + }, + { + "class": "io.openems.impl.persistence.fenecon.FeneconPersistence", + "apikey": "###APIKEY###" + } + ] +} + diff --git a/edge/template/FeneconPro.json b/setup/templates/FENECON Pro 9-12.json similarity index 97% rename from edge/template/FeneconPro.json rename to setup/templates/FENECON Pro 9-12.json index 53c054e2cc7..fa58051aa3a 100644 --- a/edge/template/FeneconPro.json +++ b/setup/templates/FENECON Pro 9-12.json @@ -96,11 +96,11 @@ { "class": "io.openems.impl.persistence.influxdb.InfluxdbPersistence", "ip": "127.0.0.1", - "fems": 0 + "fems": "###FEMS_ID###" }, { "class": "io.openems.impl.persistence.fenecon.FeneconPersistence", - "apikey": "" + "apikey": "###APIKEY###" } ] -} +} \ No newline at end of file diff --git a/setup/templates/FENECON Pro AC-Insel.json b/setup/templates/FENECON Pro AC-Insel.json new file mode 100644 index 00000000000..b4407b765fd --- /dev/null +++ b/setup/templates/FENECON Pro AC-Insel.json @@ -0,0 +1,96 @@ +{ + "things": [ + { + "class": "io.openems.impl.protocol.modbus.ModbusRtu", + "serialinterface": "/dev/ttyUSB0", + "baudrate": 9600, + "databits": 8, + "parity": "none", + "stopbits": 1, + "devices": [ + { + "class": "io.openems.impl.device.pro.FeneconPro", + "modbusUnitId": 4, + "ess": { + "id": "ess0", + "minSoc": 15 + }, + "meter": { + "id": "meter1" + } + }, + { + "class": "io.openems.impl.device.socomec.Socomec", + "modbusUnitId": 5, + "meter": { + "id": "meter0", + "type": "grid" + } + }, + { + "class": "io.openems.impl.device.kmtronic.KMTronicRelay", + "output": { + "id": "output0" + }, + "modbusUnitId": 1 + } + ] + } + ], + "scheduler": { + "class": "io.openems.impl.scheduler.SimpleScheduler", + "controllers": [ + { + "priority": 150, + "class": "io.openems.impl.controller.debuglog.DebugLogController", + "esss": [ "ess0" ], + "meters": [ "meter0", "meter1" ], + "rtc": "ess0" + }, + { + "priority": 100, + "class": "io.openems.impl.controller.asymmetric.avoidtotaldischarge.AvoidTotalDischargeController", + "esss": "ess0" + }, + { + "priority": 50, + "class": "io.openems.impl.controller.asymmetric.balancing.BalancingController", + "esss": "ess0", + "meter": "meter0" + }, + { + "priority": 1, + "class": "io.openems.impl.controller.clocksync.ClockSyncController", + "rtc": "ess0" + }, + { + "priority": 0, + "class": "io.openems.impl.controller.feneconprosetup.FeneconProSetupController", + "esss": "ess0" + }, + { + "class": "io.openems.impl.controller.acisland.AcIsland", + "minSoc": 90, + "onGridOutputChannelAddress": "output0/2", + "offGridOutputChannelAddress": "output0/3", + "maxSoc": 95, + "switchDelay": 10000, + "ess": "ess0", + "priority": 0 + } + + ] + }, + "persistence": [ + { + "class": "io.openems.impl.persistence.influxdb.InfluxdbPersistence", + "ip": "127.0.0.1", + "fems": "###FEMS_ID###" + }, + { + "class": "io.openems.impl.persistence.fenecon.FeneconPersistence", + "apikey": "###APIKEY###" + } + ] +} + diff --git a/setup/templates/FENECON Pro Cluster.json b/setup/templates/FENECON Pro Cluster.json new file mode 100644 index 00000000000..2a9d1445910 --- /dev/null +++ b/setup/templates/FENECON Pro Cluster.json @@ -0,0 +1,94 @@ +{ + "things": [ + { + "class": "io.openems.impl.protocol.modbus.ModbusRtu", + "serialinterface": "/dev/ttyUSB0", + "baudrate": 9600, + "databits": 8, + "parity": "none", + "stopbits": 1, + "devices": [ + { + "class": "io.openems.impl.device.pro.FeneconPro", + "modbusUnitId": 4, + "ess": { + "id": "ess0", + "minSoc": 15 + }, + "meter": { + "id": "meter1" + } + }, + { + "class": "io.openems.impl.device.socomec.Socomec", + "modbusUnitId": 5, + "meter": { + "id": "meter0", + "type": "grid" + } + } + ] + }, + { + "class": "io.openems.impl.protocol.modbus.ModbusRtu", + "serialinterface": "/dev/ttyUSB1", + "baudrate": 9600, + "databits": 8, + "parity": "none", + "stopbits": 1, + "devices": [ + { + "class": "io.openems.impl.device.pro.FeneconPro", + "modbusUnitId": 4, + "ess": { + "id": "ess1", + "minSoc": 15 + }, + "meter": { + "id": "meter2" + } + } + ] + } + ], + "scheduler": { + "class": "io.openems.impl.scheduler.SimpleScheduler", + "controllers": [ + { + "priority": 150, + "class": "io.openems.impl.controller.debuglog.DebugLogController", + "esss": [ "ess0", "ess1" ], + "meters": [ "meter0", "meter1", "meter2" ], + "rtc": "ess0" + }, + { + "priority": 100, + "class": "io.openems.impl.controller.asymmetric.avoidtotaldischarge.AvoidTotalDischargeController", + "esss": [ "ess0", "ess1" ] + }, + { + "priority": 50, + "class": "io.openems.impl.controller.asymmetric.balancing.BalancingController", + "esss": [ "ess0", "ess1" ], + "meter": "meter0" + }, + { + "priority": 1, + "class": "io.openems.impl.controller.clocksync.ClockSyncController", + "rtc": "ess0" + } + ] + }, + "persistence": [ + { + "class": "io.openems.impl.persistence.influxdb.InfluxdbPersistence", + "ip": "127.0.0.1", + "fems": "###FEMS_ID###" + }, + { + "class": "io.openems.impl.persistence.fenecon.FeneconPersistence", + "apikey": "###APIKEY###" + } + ] +} + diff --git a/setup/templates/FENECON Pro Heizstab.json b/setup/templates/FENECON Pro Heizstab.json new file mode 100644 index 00000000000..203b385b971 --- /dev/null +++ b/setup/templates/FENECON Pro Heizstab.json @@ -0,0 +1,107 @@ +{ + "things": [ + { + "class": "io.openems.impl.protocol.modbus.ModbusRtu", + "serialinterface": "/dev/ttyUSB0", + "baudrate": 9600, + "databits": 8, + "parity": "none", + "stopbits": 1, + "devices": [ + { + "class": "io.openems.impl.device.pro.FeneconPro", + "modbusUnitId": 4, + "ess": { + "id": "ess0", + "minSoc": 15 + }, + "meter": { + "id": "meter1" + } + }, + { + "class": "io.openems.impl.device.socomec.Socomec", + "modbusUnitId": 5, + "meter": { + "id": "meter0", + "type": "grid" + } + }, + { + "class": "io.openems.impl.device.kmtronic.KMTronicRelayRev1", + "output": { + "id": "output0" + }, + "modbusUnitId": 1 + } + ] + } + ], + "scheduler": { + "class": "io.openems.impl.scheduler.SimpleScheduler", + "controllers": [ + { + "priority": 150, + "class": "io.openems.impl.controller.debuglog.DebugLogController", + "esss": [ "ess0" ], + "meters": [ "meter0", "meter1" ], + "rtc": "ess0" + }, + { + "priority": 100, + "class": "io.openems.impl.controller.asymmetric.avoidtotaldischarge.AvoidTotalDischargeController", + "esss": "ess0" + }, + { + "priority": 50, + "class": "io.openems.impl.controller.asymmetric.balancing.BalancingController", + "esss": "ess0", + "meter": "meter0" + }, + { + "priority": 1, + "class": "io.openems.impl.controller.clocksync.ClockSyncController", + "rtc": "ess0" + }, + { + "class": "io.openems.impl.controller.channelthreshold.ChannelThresholdController", + "priority": 60, + "thresholdChannelAddress": "ess0/Soc", + "outputChannelAddress": "output0/2", + "lowerThreshold": 92, + "upperThreshold": 100, + "hysteresis": 5 + }, + { + "class": "io.openems.impl.controller.channelthreshold.ChannelThresholdController", + "priority": 59, + "thresholdChannelAddress": "ess0/Soc", + "outputChannelAddress": "output0/3", + "lowerThreshold": 94, + "upperThreshold": 100, + "hysteresis": 5 + }, + { + "class": "io.openems.impl.controller.channelthreshold.ChannelThresholdController", + "priority": 58, + "thresholdChannelAddress": "ess0/Soc", + "outputChannelAddress": "output0/4", + "lowerThreshold": 96, + "upperThreshold": 100, + "hysteresis": 5 + } + ] + }, + "persistence": [ + { + "class": "io.openems.impl.persistence.influxdb.InfluxdbPersistence", + "ip": "127.0.0.1", + "fems": "###FEMS_ID###" + }, + { + "class": "io.openems.impl.persistence.fenecon.FeneconPersistence", + "apikey": "###APIKEY###" + } + ] +} + diff --git "a/setup/templates/FENECON Pro W\303\244rmepumpe.json" "b/setup/templates/FENECON Pro W\303\244rmepumpe.json" new file mode 100644 index 00000000000..7cb313fccbd --- /dev/null +++ "b/setup/templates/FENECON Pro W\303\244rmepumpe.json" @@ -0,0 +1,103 @@ +{ + "things": [ + { + "class": "io.openems.impl.protocol.modbus.ModbusRtu", + "serialinterface": "/dev/ttyUSB0", + "baudrate": 9600, + "databits": 8, + "parity": "none", + "stopbits": 1, + "devices": [ + { + "class": "io.openems.impl.device.pro.FeneconPro", + "modbusUnitId": 4, + "ess": { + "id": "ess0", + "minSoc": 15 + }, + "meter": { + "id": "meter1" + } + }, + { + "class": "io.openems.impl.device.socomec.Socomec", + "modbusUnitId": 5, + "meter": { + "id": "meter0", + "type": "grid" + } + }, + { + "class": "io.openems.impl.device.kmtronic.KMTronicRelayRev1", + "output": { + "id": "output0" + }, + "modbusUnitId": 1 + } + ] + } + ], + "scheduler": { + "class": "io.openems.impl.scheduler.SimpleScheduler", + "controllers": [ + { + "priority": 150, + "class": "io.openems.impl.controller.debuglog.DebugLogController", + "esss": [ + "ess0" + ], + "meters": [ + "meter0", + "meter1" + ], + "rtc": "ess0" + }, + { + "priority": 100, + "class": "io.openems.impl.controller.asymmetric.avoidtotaldischarge.AvoidTotalDischargeController", + "esss": "ess0" + }, + { + "priority": 50, + "class": "io.openems.impl.controller.asymmetric.balancing.BalancingController", + "esss": "ess0", + "meter": "meter0" + }, + { + "priority": 1, + "class": "io.openems.impl.controller.clocksync.ClockSyncController", + "rtc": "ess0" + }, + { + "class": "io.openems.impl.controller.channelthreshold.ChannelThresholdController", + "priority": 60, + "thresholdChannelAddress": "ess0/Soc", + "outputChannelAddress": "output0/2", + "lowerThreshold": 0, + "upperThreshold": 40, + "hysteresis": 5 + }, + { + "class": "io.openems.impl.controller.channelthreshold.ChannelThresholdController", + "priority": 65, + "thresholdChannelAddress": "ess0/Soc", + "outputChannelAddress": "output0/3", + "lowerThreshold": 75, + "upperThreshold": 100, + "hysteresis": 5 + } + ] + }, + "persistence": [ + { + "class": "io.openems.impl.persistence.influxdb.InfluxdbPersistence", + "ip": "127.0.0.1", + "fems": "###FEMS_ID###" + }, + { + "class": "io.openems.impl.persistence.fenecon.FeneconPersistence", + "apikey": "###APIKEY###" + } + ] +} + diff --git a/ui/package-lock.json b/ui/package-lock.json index 61b43f78a4c..ffb13ea597d 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,13 +1,13 @@ { "name": "openems-ui", - "version": "1.7.0-SNAPSHOT", + "version": "2018.1", "lockfileVersion": 1, "requires": true, "dependencies": { "@angular-devkit/build-optimizer": { - "version": "0.0.34", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.0.34.tgz", - "integrity": "sha512-uSvyKtkDnfnBt6GGJ0m1nFI9IylKq6KoQil04GobhDCXFyin6Gbr50focx3jaizwDuh4v/x11fEUi5/cSUkKhA==", + "version": "0.0.35", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.0.35.tgz", + "integrity": "sha512-7JxZZAYFSCc0tP6+NrRn3b2Cd1b9d+a3+OfwVNyNsNd2unelqUMko2hm0KLbC8BXcXt/OILg1E/ZgLAXSS47nw==", "dev": true, "requires": { "loader-utils": "1.1.0", @@ -34,13 +34,14 @@ } }, "@angular-devkit/schematics": { - "version": "0.0.38", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.0.38.tgz", - "integrity": "sha512-vvyn7p/t4EKLSONGIw9jot9iMM3lEvdMDfnLkgubznIiIFxH9I+aYw9BBV2AmwE7OASHrCRpwFf7K2EqJ0f9+A==", + "version": "0.0.41", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.0.41.tgz", + "integrity": "sha512-eSXyRLM7g9NvNUwDd71iPjHEL0Zutg9PcLUSCrwFXR3Z8S6iStO2FpZACNmz5/Y7ksWLy5/1wjLuDJCHS4X/ig==", "dev": true, "requires": { "@angular-devkit/core": "0.0.22", "@ngtools/json-schema": "1.1.0", + "@schematics/schematics": "0.0.10", "minimist": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "rxjs": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.2.tgz" } @@ -53,27 +54,27 @@ } }, "@angular/cdk": { - "version": "5.0.0-rc.2", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-5.0.0-rc.2.tgz", - "integrity": "sha512-/qQu+VXwBaFbn0eZDcRmY/RFyWTxdo/sWbkhnQlpGjrjbCs4Xj3CNHJxQwBVpowkjWguisc3PQQI2mvdJ0p0Rw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-5.0.0.tgz", + "integrity": "sha512-+u67Bns23tuCUGUCWhqkR/+onCwB4ObRURUv7ar2+BHw5VIvzML+IOCi1BJRF7gqvL+IVYQpLuY2cQh0J2SbBQ==", "requires": { "tslib": "https://registry.npmjs.org/tslib/-/tslib-1.8.0.tgz" } }, "@angular/cli": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-1.5.5.tgz", - "integrity": "sha512-qAooJraZwT9o2W7yx6gY6fnc7PEMlGzu60ELZJfC51MnoYMPKiIEFYeWanCSNju1P7jfpeBXuwp1qEMZCX73Zw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-1.6.0.tgz", + "integrity": "sha512-X049QAgSKy5J48byyo3T6iBTHubTC66QBMshMpTT7PWAaSq3HpPPE1xW0WwgFIXZWMQIsmncaqPwmnFmxljUdw==", "dev": true, "requires": { - "@angular-devkit/build-optimizer": "0.0.34", - "@angular-devkit/schematics": "0.0.38", + "@angular-devkit/build-optimizer": "0.0.35", + "@angular-devkit/schematics": "0.0.41", "@ngtools/json-schema": "1.1.0", - "@ngtools/webpack": "1.8.5", - "@schematics/angular": "0.1.8", + "@ngtools/webpack": "1.9.0", + "@schematics/angular": "0.1.10", "autoprefixer": "6.7.7", "chalk": "2.2.2", - "circular-dependency-plugin": "3.0.0", + "circular-dependency-plugin": "4.3.0", "common-tags": "1.5.1", "copy-webpack-plugin": "4.2.3", "core-object": "3.1.5", @@ -82,9 +83,9 @@ "denodeify": "1.2.1", "ember-cli-string-utils": "1.1.0", "exports-loader": "0.6.4", - "extract-text-webpack-plugin": "3.0.0", + "extract-text-webpack-plugin": "3.0.2", "file-loader": "1.1.5", - "fs-extra": "4.0.2", + "fs-extra": "4.0.3", "glob": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "html-webpack-plugin": "2.30.1", "istanbul-instrumenter-loader": "2.0.0", @@ -114,15 +115,15 @@ "style-loader": "0.13.2", "stylus": "0.54.5", "stylus-loader": "3.0.1", - "uglifyjs-webpack-plugin": "1.0.0", + "uglifyjs-webpack-plugin": "1.1.2", "url-loader": "0.6.2", - "webpack": "3.8.1", - "webpack-concat-plugin": "1.4.0", + "webpack": "3.10.0", + "webpack-concat-plugin": "1.4.2", "webpack-dev-middleware": "1.12.2", - "webpack-dev-server": "2.9.5", + "webpack-dev-server": "2.9.7", "webpack-merge": "4.1.1", "webpack-sources": "1.1.0", - "webpack-subresource-integrity": "1.0.1", + "webpack-subresource-integrity": "1.0.3", "zone.js": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.18.tgz" }, "dependencies": { @@ -223,9 +224,9 @@ "dev": true }, "@angular/material": { - "version": "5.0.0-rc.2", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-5.0.0-rc.2.tgz", - "integrity": "sha512-ecwzpNItU3mFjHxq802dkvMKfuZ3A18P+eSmXRDvLPBW6G0egm3mCincEepESQ75pRkRE35CSeYR/Peiy7Hzww==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-5.0.0.tgz", + "integrity": "sha512-rzF061r4aYgaf2WI12Jk0+Rd4c1VBObdeMDFWRa3XKIcvETtkz+DXFH1n+vIC4YabfPgrdJRPrzdrZ7fKhRz6g==", "requires": { "tslib": "https://registry.npmjs.org/tslib/-/tslib-1.8.0.tgz" } @@ -267,9 +268,9 @@ "dev": true }, "@ngtools/webpack": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-1.8.5.tgz", - "integrity": "sha512-caqEQuxypjZTQkO4wRykX4Mp7FCHUApTym5Yjr6VuM+zR4uVzjBceIaT/3a0X+p6iU4dmd6DpT2y96xki/YVSQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-1.9.0.tgz", + "integrity": "sha512-+9EFOELj9D7zarsKTiIFSbTL2Pr3jYdRJ/cEuSoTxzZUDq7f3urq9ILbcy3DTaDlZs2CCYKwgz+In8QnDtw4fg==", "dev": true, "requires": { "chalk": "2.2.2", @@ -324,14 +325,20 @@ "integrity": "sha1-AA8thjxMlMgY4UFu9DzKLFwMWEg=" }, "@schematics/angular": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.1.8.tgz", - "integrity": "sha512-88QrOoS0gQ6BdKulP01dTPmfPwLhvzb4jCcKkp0g8kvzTkIadlORmC9bQtucJI5huPU2bglVfmPgAk2ZwMSLDA==", + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.1.10.tgz", + "integrity": "sha512-ykq4FL0WTygkpvIcGDxnxHHT2uvJMWseDeAujmfyZpzdT9X22GOTURNo3LjvOIhhVUpMVZvnAYqjV46KqB702g==", "dev": true, "requires": { "@angular-devkit/core": "0.0.22" } }, + "@schematics/schematics": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/@schematics/schematics/-/schematics-0.0.10.tgz", + "integrity": "sha512-9vr9W1X6oRp42pbiGRIk3L+T6SoFtHlAGrzbh6rbFQDNXT4UCHarqDigow+DEL6PR2ptXZO9WeLcad4it7zNyA==", + "dev": true + }, "@types/d3": { "version": "4.12.0", "resolved": "https://registry.npmjs.org/@types/d3/-/d3-4.12.0.tgz", @@ -372,12 +379,12 @@ "@types/d3-array": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-1.2.1.tgz", - "integrity": "sha512-YBaAfimGdWE4nDuoGVKsH89/dkz2hWZ0i8qC+xxqmqi+XJ/aXiRF0jPtzXmN7VdkpVjy1xuDmM5/m1FNuB6VWA==" + "integrity": "sha1-5IlgUgjUahydmA0uV3L6nHXZ7GU=" }, "@types/d3-axis": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-1.0.9.tgz", - "integrity": "sha512-fNUnI2a0F3xiE/nGrTdDpZG4sdcRIB4X59p9jgY8O7RQiKrVqyb433YCCYSqVID4CVyoq5v3bSFliUEk0FOMsw==", + "integrity": "sha1-Ys57yNBDVCmM2lfz8dH4Vq1puJo=", "requires": { "@types/d3-selection": "1.2.0" } @@ -413,7 +420,7 @@ "@types/d3-drag": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-1.2.0.tgz", - "integrity": "sha512-AePmm0sXj0Tpl0uQWvwmbAf1QR3yCy9aRhjJ9mRDDSZlHBdY0SCpUtdZC9uG9Q+pyHT/dEt1R2FT/sj+5k/bVA==", + "integrity": "sha1-XuYnlDLIlPhcty/NqRGpWbrhGVI=", "requires": { "@types/d3-selection": "1.2.0" } @@ -431,12 +438,12 @@ "@types/d3-force": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-1.1.0.tgz", - "integrity": "sha512-a39Uu/ltLaMpj6K0elEB1oAqhx9rlTB5X/O75uTUqyTW2CfjhPXg6hFsX1lF8oeMc29kqGJZ4g9Pf6mET25bVw==" + "integrity": "sha1-QJJco1ErY71CT3yWheF4G1sKHX4=" }, "@types/d3-format": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-1.2.1.tgz", - "integrity": "sha512-dXhA9jzCbzu6Va8ZVUQ60nu6jqA5vhPhKGR4nY3lDYfjT05GyKEKuEhfwTaSTybWczY4nLEkzv9wLQCQd5+3cA==" + "integrity": "sha1-lDX7F3HS+/aoWMkyGPQJfJqjlsE=" }, "@types/d3-geo": { "version": "1.9.4", @@ -462,7 +469,7 @@ "@types/d3-path": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.6.tgz", - "integrity": "sha512-YHW4cs+wOU9gFUzudjJs9TkrB/8GOgKhq32ZyNaZ2rzZjOhkqG486sGr9XSh4C91CcgIg1FRGoDaN29Ropx9nw==" + "integrity": "sha1-wafS3Aeylf3RyE2r5EBN+ZG0hpM=" }, "@types/d3-polygon": { "version": "1.0.5", @@ -495,7 +502,7 @@ "@types/d3-scale": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-1.0.10.tgz", - "integrity": "sha512-2CCyRc9o7oawNqNXuv6P1QBFH4PYnZt4IZK6J5nKykQjzezPC/RqCeRDBTk0JhBC8pLcLWYzGR6G2zG2OUwPag==", + "integrity": "sha1-jFwdylShWe7QQrRnGduzvbfoyEI=", "requires": { "@types/d3-time": "1.0.7" } @@ -508,7 +515,7 @@ "@types/d3-shape": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.2.1.tgz", - "integrity": "sha512-y0QmQtKns0IHBoG80yGLo6rmznHjZs/JODxc9kOgQgkCUe2e07X9DPghXE1KbTTAIr9U85Xm8YSbSzx/ytxyYg==", + "integrity": "sha1-ysLZ8BIvFzIgwyyMFS3ELuk0nfI=", "requires": { "@types/d3-path": "1.0.6" } @@ -516,12 +523,12 @@ "@types/d3-time": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-1.0.7.tgz", - "integrity": "sha512-X5ZQYiJIM38XygNwld4gZ++Vtw2ftgo3KOfZOY4n/sCudUxclxf/3THBvuG8UqSV+EQ0ezYjT5eyvcrrmixOWA==" + "integrity": "sha1-QmbXyb4V+oElaojR0FLWHNjcVyw=" }, "@types/d3-time-format": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.1.0.tgz", - "integrity": "sha512-/myT3I7EwlukNOX2xVdMzb8FRgNzRMpsZddwst9Ld/VFe6LyJyRp0s32l/V9XoUzk+Gqu56F/oGk6507+8BxrA==" + "integrity": "sha1-AR4Pt5N740qaj1gK4eLy8TNqiiI=" }, "@types/d3-timer": { "version": "1.0.6", @@ -531,7 +538,7 @@ "@types/d3-transition": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-1.1.1.tgz", - "integrity": "sha512-GHTghl0YYB8gGgbyKxVLHyAp9Na0HqsX2U7M0u0lGw4IdfEaslooykweZ8fDHW13T+KZeZAuzhbmqBZVFO+6kg==", + "integrity": "sha1-wgn85qlm1mljVt1CsJGpxsx5kp8=", "requires": { "@types/d3-selection": "1.2.0" } @@ -539,12 +546,12 @@ "@types/d3-voronoi": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/@types/d3-voronoi/-/d3-voronoi-1.1.7.tgz", - "integrity": "sha512-/dHFLK5jhXTb/W4XEQcFydVk8qlIAo85G3r7+N2fkBFw190l0R1GQ8C1VPeXBb2GfSU5GbT2hjlnE7i7UY5Gvg==" + "integrity": "sha1-wKFFzwQ5WSfgFwb/bE/4Ncl6js4=" }, "@types/d3-zoom": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-1.7.0.tgz", - "integrity": "sha512-eIivt2ehMUXqS0guuVzRSMr5RGhO958g9EKxIJv3Z23suPnX4VQI9k1TC/bLuwKq0IWp9a1bEEcIy+PNJv9BtA==", + "integrity": "sha1-EiG79kNIIPBEyAtVHFUZuBcAiWE=", "requires": { "@types/d3-interpolate": "1.1.6", "@types/d3-selection": "1.2.0" @@ -895,7 +902,7 @@ "dev": true, "requires": { "browserslist": "1.7.7", - "caniuse-db": "1.0.30000775", + "caniuse-db": "1.0.30000782", "normalize-range": "0.1.2", "num2fraction": "1.2.2", "postcss": "5.2.18", @@ -1271,8 +1278,8 @@ "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", "dev": true, "requires": { - "caniuse-db": "1.0.30000775", - "electron-to-chromium": "1.3.27" + "caniuse-db": "1.0.30000782", + "electron-to-chromium": "1.3.28" } }, "buffer": { @@ -1374,15 +1381,15 @@ "dev": true, "requires": { "browserslist": "1.7.7", - "caniuse-db": "1.0.30000775", + "caniuse-db": "1.0.30000782", "lodash.memoize": "4.1.2", "lodash.uniq": "4.5.0" } }, "caniuse-db": { - "version": "1.0.30000775", - "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000775.tgz", - "integrity": "sha1-BLzN0CFO3yW5f2GglmCfetaQQzM=", + "version": "1.0.30000782", + "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000782.tgz", + "integrity": "sha1-2IFbzhV4w1Cs7REyUHMBIF4Pq1M=", "dev": true }, "caseless": { @@ -1521,9 +1528,9 @@ } }, "circular-dependency-plugin": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-3.0.0.tgz", - "integrity": "sha1-m2hpLjWw41EJmNAWS2rlARvqV2A=", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-4.3.0.tgz", + "integrity": "sha512-L3W9L1S0wC64rq+QSaZzmWnJW7cVBgimxI2lNEFEX5biwlRG8EHRM68JFi+CX5ZkCGUWJHIpnhdVs181Zlq3wA==", "dev": true }, "clap": { @@ -2218,7 +2225,7 @@ "d3-drag": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.1.tgz", - "integrity": "sha512-Cg8/K2rTtzxzrb0fmnYOUeZHvwa4PHzwXOLZZPwtEs2SKLLKLXeYwZKBB+DlOxUvFmarOnmt//cU4+3US2lyyQ==", + "integrity": "sha1-343UxQL7SQ/HRiBGqK2YpcR5KC0=", "requires": { "d3-dispatch": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.3.tgz", "d3-selection": "1.2.0" @@ -2363,7 +2370,7 @@ "d3-request": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/d3-request/-/d3-request-1.0.6.tgz", - "integrity": "sha512-FJj8ySY6GYuAJHZMaCQ83xEYE4KbkPkmxZ3Hu6zA1xxG2GD+z6P+Lyp+zjdsHf0xEbp2xcluDI50rCS855EQ6w==", + "integrity": "sha1-oQRKnvTsKMgkFxyTefrm15R0sZ8=", "requires": { "d3-collection": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.4.tgz", "d3-dispatch": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.3.tgz", @@ -2738,9 +2745,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.27", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.27.tgz", - "integrity": "sha1-eOy4o5kGYYe7N07t412ccFZagD0=", + "version": "1.3.28", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.28.tgz", + "integrity": "sha1-jdTmRYCGZE6fnwoc8y4qH53/2e4=", "dev": true }, "elliptic": { @@ -2897,12 +2904,12 @@ "dev": true }, "errno": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz", - "integrity": "sha1-uJbiOp5ei6M4cfyZar02NfyaHH0=", + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.5.tgz", + "integrity": "sha512-tv2H+e3KBnMmNRuoVG24uorOj3XfYo+/nJJd07PUISRr0kaMKQKL5kyD+6ANXk1ZIIsvbORsjvHnCfC4KIc7uQ==", "dev": true, "requires": { - "prr": "0.0.0" + "prr": "1.0.1" } }, "error-ex": { @@ -3267,9 +3274,9 @@ } }, "extract-text-webpack-plugin": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.0.tgz", - "integrity": "sha1-kMqnkHvESfM1AF46x1MrQbAN5hI=", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.2.tgz", + "integrity": "sha512-bt/LZ4m5Rqt/Crl2HiKuAl/oqg0psx1tsTLkvWbJen1CtD+fftkZhMaQ9HOtY2gWsl2Wq+sABmMVi9z3DhKWQQ==", "dev": true, "requires": { "async": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", @@ -3466,9 +3473,9 @@ } }, "fs-extra": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.2.tgz", - "integrity": "sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s=", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", "dev": true, "requires": { "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", @@ -3850,7 +3857,7 @@ "ncname": "1.0.0", "param-case": "2.1.1", "relateurl": "0.2.7", - "uglify-js": "3.2.0" + "uglify-js": "3.2.2" }, "dependencies": { "commander": { @@ -4946,7 +4953,7 @@ "integrity": "sha1-zBJg9RyQCp7A2R+2mYE54CUHtjs=", "dev": true, "requires": { - "errno": "0.1.4", + "errno": "0.1.5", "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "image-size": "0.5.5", "mime": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", @@ -5431,7 +5438,7 @@ "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", "dev": true, "requires": { - "errno": "0.1.4", + "errno": "0.1.5", "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz" } }, @@ -7452,9 +7459,9 @@ } }, "prr": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", - "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", "dev": true }, "pseudomap": { @@ -7546,13 +7553,6 @@ "integrity": "sha1-DPf4T5Rj/wrlHExLFC2VvjdyTZw=", "dev": true }, - "queueing-subject": { - "version": "https://registry.npmjs.org/queueing-subject/-/queueing-subject-0.1.1.tgz", - "integrity": "sha1-Q/hXsrJjJ2/0GM3YZbfXjV1kHZ0=", - "requires": { - "rxjs": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.2.tgz" - } - }, "randomatic": { "version": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", "integrity": "sha1-x6vpzIuHwLqodrGf3oP9RkeX44w=", @@ -8995,9 +8995,9 @@ "dev": true }, "uglify-js": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.2.0.tgz", - "integrity": "sha512-L98DlTshoPGnZGF8pr3MoE+CCo6n9joktHNHMPkckeBV8xTVc4CWtC0kGGhQsIvnX2Ug4nXFTAeE7SpTrPX2tg==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.2.2.tgz", + "integrity": "sha512-++1NO/zZIEdWf6cDIGceSJQPX31SqIpbVAHwFG5+240MtZqPG/NIPoinj8zlXQtAfMBqEt1Jyv2FiLP3n9gVhQ==", "dev": true, "requires": { "commander": "2.12.2", @@ -9025,16 +9025,16 @@ "optional": true }, "uglifyjs-webpack-plugin": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.0.0.tgz", - "integrity": "sha1-HFi12x7QQ+AkrvZvit4l4UggYmQ=", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.1.2.tgz", + "integrity": "sha512-k07cmJTj+8vZMSc3BaQ9uW7qVl2MqDts4ti4KaNACXEcXSw2vQM2S8olSk/CODxvcSFGvUHzNSqA8JQlhgUJPw==", "dev": true, "requires": { "cacache": "10.0.1", "find-cache-dir": "1.0.0", "schema-utils": "0.3.0", - "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "uglify-es": "3.2.0", + "source-map": "0.6.1", + "uglify-es": "3.2.2", "webpack-sources": "1.1.0", "worker-farm": "1.5.2" }, @@ -9045,22 +9045,20 @@ "integrity": "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA==", "dev": true }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, "uglify-es": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.2.0.tgz", - "integrity": "sha512-eD4rjK4o6rzrvE1SMZJLQFEVMnWRUyIu6phJ0BXk5TIthMmP5B4QP0HI8o3bkQB5wf1N4WHA0leZAQyQBAd+Jg==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.2.2.tgz", + "integrity": "sha512-l+s5VLzFwGJfS+fbqaGf/Dfwo1MF13jLOF2ekL0PytzqEqQ6cVppvHf4jquqFok+35USMpKjqkYxy6pQyUcuug==", "dev": true, "requires": { "commander": "2.12.2", "source-map": "0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } } } } @@ -9359,9 +9357,9 @@ } }, "webpack": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.8.1.tgz", - "integrity": "sha1-sWloqBEAq+YWCLAVPJFZ74uyvYM=", + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.10.0.tgz", + "integrity": "sha512-fxxKXoicjdXNUMY7LIdY89tkJJJ0m1Oo8PQutZ5rLgWbV5QVKI15Cn7+/IHnRTd3vfKfiwBx6SBqlorAuNA8LA==", "dev": true, "requires": { "acorn": "5.2.1", @@ -9642,9 +9640,9 @@ } }, "webpack-concat-plugin": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/webpack-concat-plugin/-/webpack-concat-plugin-1.4.0.tgz", - "integrity": "sha1-pus/AILQPHnY7i8VGMf0jkTuEsU=", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/webpack-concat-plugin/-/webpack-concat-plugin-1.4.2.tgz", + "integrity": "sha512-HdV2xOq4twtL2ThR9NSCCQ888v1JBMpJfm3k2mA1I5LkS2+/6rv8q/bb9yTSaR0fVaMtANZi4Wkz0xc33MAt6w==", "dev": true, "requires": { "md5": "2.2.1", @@ -9748,9 +9746,9 @@ } }, "webpack-dev-server": { - "version": "2.9.5", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.9.5.tgz", - "integrity": "sha512-o0lS6enIxyOPiRJTh8vcgK5TsGNTn7lH1q/pNniAgs46mCE8sQYeqv7Y/oAIh/+u4kiBsFizLJo5EWC+ezz6FQ==", + "version": "2.9.7", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.9.7.tgz", + "integrity": "sha512-Pu7uoQFgQj5RE5wmlfkpYSzihMKxulwEuO2xCsaMnAnyRSApwoVi3B8WCm9XbigyWTHaIMzYGkB90Vr6leAeTQ==", "dev": true, "requires": { "ansi-html": "0.0.7", @@ -9872,9 +9870,9 @@ } }, "webpack-subresource-integrity": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-1.0.1.tgz", - "integrity": "sha1-H8CdRkl9pm5GdDoqUdLMOFucsO0=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-1.0.3.tgz", + "integrity": "sha1-wGBtQAkLBwzeQovsjfNgMhbkcus=", "dev": true, "requires": { "webpack-core": "0.6.9" @@ -9947,7 +9945,7 @@ "integrity": "sha512-XxiQ9kZN5n6mmnW+mFJ+wXjNNI/Nx4DIdaAKLX1Bn6LYBWlN/zaBhu34DQYPZ1AJobQuu67S2OfDdNSVULvXkQ==", "dev": true, "requires": { - "errno": "0.1.4", + "errno": "0.1.5", "xtend": "4.0.1" } }, diff --git a/ui/package.json b/ui/package.json index d4ba9857791..4448a60e1d4 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "openems-ui", - "version": "1.8.0-SNAPSHOT", + "version": "2018.1", "license": "AGPL", "scripts": { "ng": "ng", @@ -15,14 +15,14 @@ "private": true, "dependencies": { "@angular/animations": "^5.0.0", - "@angular/cdk": "5.0.0-rc.2", + "@angular/cdk": "^5.0.0", "@angular/common": "^5.0.0", "@angular/compiler": "^5.0.0", "@angular/core": "^5.0.0", "@angular/flex-layout": "2.0.0-beta.10-4905443", "@angular/forms": "^5.0.0", "@angular/http": "^5.0.0", - "@angular/material": "5.0.0-rc.2", + "@angular/material": "^5.0.0", "@angular/platform-browser": "^5.0.0", "@angular/platform-browser-dynamic": "^5.0.0", "@angular/platform-server": "^5.0.0", @@ -53,7 +53,6 @@ "ng2-charts": "^1.6.0", "ng2-cookies": "^1.0.12", "ngx-loading": "^1.0.9", - "queueing-subject": "^0.1.1", "roboto-fontface": "0.8.0", "rxjs": "^5.5.2", "rxjs-websockets": "4.0.0", @@ -61,7 +60,7 @@ "zone.js": "^0.8.14" }, "devDependencies": { - "@angular/cli": "1.5.5", + "@angular/cli": "1.6.0", "@angular/compiler-cli": "^5.0.0", "@angular/language-service": "^5.0.0", "@types/jasmine": "~2.5.53", diff --git a/ui/pom.xml b/ui/pom.xml index 22d120aebca..b556cc90027 100644 --- a/ui/pom.xml +++ b/ui/pom.xml @@ -7,7 +7,7 @@ io.openems pom - 1.7.1 + 2018.1 edge pom diff --git a/ui/src/app/about/about.component.html b/ui/src/app/about/about.component.html index b080627a381..eae7a2cdacf 100644 --- a/ui/src/app/about/about.component.html +++ b/ui/src/app/about/about.component.html @@ -16,14 +16,14 @@
  • About.Sourcecode
  • -
  • + +
  • + + About.Build: v2018.1 +
  • diff --git a/ui/src/app/device/overview/energymonitor/chart/section/abstractsection.component.ts b/ui/src/app/device/overview/energymonitor/chart/section/abstractsection.component.ts index f5045195bf8..07709742882 100644 --- a/ui/src/app/device/overview/energymonitor/chart/section/abstractsection.component.ts +++ b/ui/src/app/device/overview/energymonitor/chart/section/abstractsection.component.ts @@ -102,12 +102,14 @@ export class EnergyFlow { export abstract class AbstractSection { + public url: string = window.location.href; public valuePath: string = ""; public outlinePath: string = ""; public energyFlow: EnergyFlow; public square: SvgSquare; public squarePosition: SvgSquarePosition; public name: string = ""; + public sectionId: string = ""; protected valueRatio: number = 0; protected valueText: string = ""; @@ -126,6 +128,7 @@ export abstract class AbstractSection { public color: string, protected translate: TranslateService ) { + this.sectionId = translateName; this.name = translate.instant(translateName); this.energyFlow = this.initEnergyFlow(0); } diff --git a/ui/src/app/device/overview/energymonitor/chart/section/section.component.html b/ui/src/app/device/overview/energymonitor/chart/section/section.component.html index 672da885c54..de23d05c4df 100644 --- a/ui/src/app/device/overview/energymonitor/chart/section/section.component.html +++ b/ui/src/app/device/overview/energymonitor/chart/section/section.component.html @@ -10,18 +10,13 @@ - - - + \ No newline at end of file diff --git a/ui/src/app/shared/device/config.ts b/ui/src/app/shared/device/config.ts index d1c20fac1da..adf0798fbc9 100644 --- a/ui/src/app/shared/device/config.ts +++ b/ui/src/app/shared/device/config.ts @@ -143,9 +143,20 @@ export class ConfigImpl implements DefaultTypes.Config { this.evcsDevices = evcsDevices; } + public getStateChannels(): DefaultTypes.ChannelAddresses { + let result: DefaultTypes.ChannelAddresses = {} + + // Set "ignoreNatures" + for (let thingId in this.config.things) { + result[thingId] = ["State"]; + } + return result; + } + + /** - * Return ChannelAddresses of power channels - */ + * Return ChannelAddresses of power channels + */ public getPowerChannels(): DefaultTypes.ChannelAddresses { let ignoreNatures = { EssClusterNature: true }; let result: DefaultTypes.ChannelAddresses = {} @@ -234,6 +245,7 @@ export class ConfigImpl implements DefaultTypes.Config { } } // basic channels + merge(this.getStateChannels()); merge(this.getPowerChannels()); merge(this.getEssSocChannels()); // widget channels diff --git a/ui/src/polyfills.ts b/ui/src/polyfills.ts index 8675ae82049..87abf4d27d2 100644 --- a/ui/src/polyfills.ts +++ b/ui/src/polyfills.ts @@ -56,7 +56,7 @@ import 'web-animations-js'; // Run `npm install --save web-animations-js`. /*************************************************************************************************** - * Zone JS is required by Angular itself. + * Zone JS is required by default for Angular itself. */ import 'zone.js/dist/zone'; // Included with Angular CLI. diff --git a/ui/tslint.json b/ui/tslint.json index 20ad878fe78..a2e30eff294 100644 --- a/ui/tslint.json +++ b/ui/tslint.json @@ -130,7 +130,6 @@ "app", "kebab-case" ], - "angular-whitespace": [true, "check-interpolation"], "no-output-on-prefix": true, "use-input-property-decorator": true, "use-output-property-decorator": true, diff --git a/ui/yarn.lock b/ui/yarn.lock index c274a0d5a54..7b8f5ced82d 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -2,9 +2,9 @@ # yarn lockfile v1 -"@angular-devkit/build-optimizer@~0.0.34": - version "0.0.34" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.0.34.tgz#47a0482f5687db79d102cf9d416cf6fa6774d702" +"@angular-devkit/build-optimizer@~0.0.35": + version "0.0.36" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.0.36.tgz#e816ee9be22dbb777724f0281acfa72cfff184b7" dependencies: loader-utils "^1.1.0" source-map "^0.5.6" @@ -17,12 +17,13 @@ dependencies: source-map "^0.5.6" -"@angular-devkit/schematics@~0.0.38": - version "0.0.39" - resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-0.0.39.tgz#8821482d21f3d16798474983599c592063c881e7" +"@angular-devkit/schematics@~0.0.40": + version "0.0.42" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-0.0.42.tgz#34eea7136455545c8abd21edf94a36870a073fea" dependencies: "@angular-devkit/core" "0.0.22" "@ngtools/json-schema" "^1.1.0" + "@schematics/schematics" "0.0.11" minimist "^1.2.0" rxjs "^5.5.2" @@ -32,24 +33,24 @@ dependencies: tslib "^1.7.1" -"@angular/cdk@5.0.0-rc.2": - version "5.0.0-rc.2" - resolved "https://registry.yarnpkg.com/@angular/cdk/-/cdk-5.0.0-rc.2.tgz#65a76381a0481e92990af4a105cd3bcbc53ee2af" +"@angular/cdk@^5.0.0": + version "5.0.4" + resolved "https://registry.yarnpkg.com/@angular/cdk/-/cdk-5.0.4.tgz#f76a268e404f41aff0e908b21e7de9a5dfc07150" dependencies: tslib "^1.7.1" -"@angular/cli@1.5.5": - version "1.5.5" - resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-1.5.5.tgz#400ef304d88b13a82a72a4c4c42e2b53a0db04fd" +"@angular/cli@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-1.6.0.tgz#eba521f6a8e4c2db628300baddbc4da13ca96998" dependencies: - "@angular-devkit/build-optimizer" "~0.0.34" - "@angular-devkit/schematics" "~0.0.38" + "@angular-devkit/build-optimizer" "~0.0.35" + "@angular-devkit/schematics" "~0.0.40" "@ngtools/json-schema" "1.1.0" - "@ngtools/webpack" "1.8.5" - "@schematics/angular" "~0.1.8" + "@ngtools/webpack" "1.9.0" + "@schematics/angular" "~0.1.10" autoprefixer "^6.5.3" chalk "~2.2.0" - circular-dependency-plugin "^3.0.0" + circular-dependency-plugin "^4.2.1" common-tags "^1.3.1" copy-webpack-plugin "^4.1.1" core-object "^3.1.0" @@ -58,7 +59,7 @@ denodeify "^1.2.1" ember-cli-string-utils "^1.0.0" exports-loader "^0.6.3" - extract-text-webpack-plugin "3.0.0" + extract-text-webpack-plugin "^3.0.2" file-loader "^1.1.5" fs-extra "^4.0.0" glob "^7.0.3" @@ -89,10 +90,10 @@ style-loader "^0.13.1" stylus "^0.54.5" stylus-loader "^3.0.1" - uglifyjs-webpack-plugin "1.0.0" + uglifyjs-webpack-plugin "~1.1.2" url-loader "^0.6.2" - webpack "~3.8.1" - webpack-concat-plugin "1.4.0" + webpack "~3.10.0" + webpack-concat-plugin "^1.4.2" webpack-dev-middleware "~1.12.0" webpack-dev-server "~2.9.3" webpack-merge "^4.1.0" @@ -151,9 +152,9 @@ version "5.0.1" resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-5.0.1.tgz#869e09dbd6e3d95c117c062d21dd1fd920ad44d6" -"@angular/material@5.0.0-rc.2": - version "5.0.0-rc.2" - resolved "https://registry.yarnpkg.com/@angular/material/-/material-5.0.0-rc.2.tgz#c96bb3295787aa84aa3788d776e15611f77a70ed" +"@angular/material@^5.0.0": + version "5.0.4" + resolved "https://registry.yarnpkg.com/@angular/material/-/material-5.0.4.tgz#8efb2fb12023711dbdaac5dc7b588096b40b0f64" dependencies: tslib "^1.7.1" @@ -187,9 +188,9 @@ version "1.1.0" resolved "https://registry.yarnpkg.com/@ngtools/json-schema/-/json-schema-1.1.0.tgz#c3a0c544d62392acc2813a42c8a0dc6f58f86922" -"@ngtools/webpack@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-1.8.5.tgz#f35b646f58db1d4ac5938031051a0f9187d91961" +"@ngtools/webpack@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-1.9.0.tgz#ef395c45be2de9beb93a2b9f5f171d28c344eb10" dependencies: chalk "~2.2.0" enhanced-resolve "^3.1.0" @@ -203,12 +204,16 @@ version "9.0.1" resolved "https://registry.yarnpkg.com/@ngx-translate/core/-/core-9.0.1.tgz#000f2d863c4c94c818e1416ef43cca2c5c0c5848" -"@schematics/angular@~0.1.8": - version "0.1.9" - resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-0.1.9.tgz#f4bd5da3da0e9414db7ee2a967a4789959c47a24" +"@schematics/angular@~0.1.10": + version "0.1.11" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-0.1.11.tgz#b5f15320bbb60969d66c76a8ef6545058ac81ece" dependencies: "@angular-devkit/core" "0.0.22" +"@schematics/schematics@0.0.11": + version "0.0.11" + resolved "https://registry.yarnpkg.com/@schematics/schematics/-/schematics-0.0.11.tgz#c8f70f270ed38f29b2873248126fd59abd635862" + "@types/d3-array@*": version "1.2.1" resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-1.2.1.tgz#e489605208d46a1c9d980d2e5772fa9c75d9ec65" @@ -459,6 +464,10 @@ ajv-keywords@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.0.tgz#a296e17f7bfae7c1ce4f7e0de53d29cb32162df0" +ajv-keywords@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" + ajv@^4.9.1: version "4.11.8" resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" @@ -988,9 +997,9 @@ bytes@2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.5.0.tgz#4c9423ea2d252c270c41b2bdefeff9bb6b62c06a" -cacache@^10.0.0: - version "10.0.1" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.1.tgz#3e05f6e616117d9b54665b1b20c8aeb93ea5d36f" +cacache@^10.0.1: + version "10.0.2" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.2.tgz#105a93a162bbedf3a25da42e1939ed99ffb145f8" dependencies: bluebird "^3.5.0" chownr "^1.0.1" @@ -1155,9 +1164,9 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.1" safe-buffer "^5.0.1" -circular-dependency-plugin@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/circular-dependency-plugin/-/circular-dependency-plugin-3.0.0.tgz#9b68692e35b0e3510998d0164b6ae5011bea5760" +circular-dependency-plugin@^4.2.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/circular-dependency-plugin/-/circular-dependency-plugin-4.3.0.tgz#2a12824e584546e1aeea5865b7bf234a11c4a695" clap@^1.0.9: version "1.2.0" @@ -1289,6 +1298,10 @@ commander@2, commander@2.11.x, commander@^2.9.0, commander@~2.11.0: version "2.11.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" +commander@~2.12.1: + version "2.12.2" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" + common-tags@^1.3.1: version "1.4.0" resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.4.0.tgz#1187be4f3d4cf0c0427d43f74eef1f73501614c0" @@ -2482,9 +2495,9 @@ extglob@^0.3.1: dependencies: is-extglob "^1.0.0" -extract-text-webpack-plugin@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.0.tgz#90caa7907bc449f335005e3ac7532b41b00de612" +extract-text-webpack-plugin@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.2.tgz#5f043eaa02f9750a9258b78c0a6e0dc1408fb2f7" dependencies: async "^2.4.1" loader-utils "^1.1.0" @@ -4933,12 +4946,6 @@ querystringify@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-1.0.0.tgz#6286242112c5b712fa654e526652bf6a13ff05cb" -queueing-subject@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/queueing-subject/-/queueing-subject-0.1.1.tgz#43f857b2b263276ff418cdd865b7d78d5d641d9d" - dependencies: - rxjs "^5.0.1" - randomatic@^1.1.3: version "1.1.7" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" @@ -5226,12 +5233,6 @@ rxjs-websockets@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/rxjs-websockets/-/rxjs-websockets-4.0.0.tgz#a8d06c74b8629a9f9d56450eda5c3177542c80f4" -rxjs@^5.0.1: - version "5.4.3" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.4.3.tgz#0758cddee6033d68e0fd53676f0f3596ce3d483f" - dependencies: - symbol-observable "^1.0.1" - rxjs@^5.5.2: version "5.5.2" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.2.tgz#28d403f0071121967f18ad665563255d54236ac3" @@ -5285,6 +5286,13 @@ schema-utils@^0.3.0: dependencies: ajv "^5.0.0" +schema-utils@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.3.tgz#e2a594d3395834d5e15da22b48be13517859458e" + dependencies: + ajv "^5.0.0" + ajv-keywords "^2.1.0" + scss-tokenizer@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1" @@ -5361,6 +5369,10 @@ send@0.15.4: range-parser "~1.2.0" statuses "~1.3.1" +serialize-javascript@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.4.0.tgz#7c958514db6ac2443a8abc062dc9f7886a7f6005" + serve-index@^1.7.2: version "1.9.0" resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.0.tgz#d2b280fc560d616ee81b48bf0fa82abed2485ce7" @@ -5967,11 +5979,11 @@ typescript@~2.6.1: version "2.6.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4" -uglify-es@^3.1.3: - version "3.1.9" - resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.1.9.tgz#6c82df628ac9eb7af9c61fd70c744a084abe6161" +uglify-es@^3.3.4: + version "3.3.5" + resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.5.tgz#cf7e695da81999f85196b15e2978862f13212f88" dependencies: - commander "~2.11.0" + commander "~2.12.1" source-map "~0.6.1" uglify-js@3.0.x: @@ -5994,18 +6006,6 @@ uglify-to-browserify@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" -uglifyjs-webpack-plugin@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.0.0.tgz#1c58b5db1ed043e024aef66f8ade25e148206264" - dependencies: - cacache "^10.0.0" - find-cache-dir "^1.0.0" - schema-utils "^0.3.0" - source-map "^0.5.6" - uglify-es "^3.1.3" - webpack-sources "^1.0.1" - worker-farm "^1.4.1" - uglifyjs-webpack-plugin@^0.4.6: version "0.4.6" resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz#b951f4abb6bd617e66f63eb891498e391763e309" @@ -6014,6 +6014,19 @@ uglifyjs-webpack-plugin@^0.4.6: uglify-js "^2.8.29" webpack-sources "^1.0.1" +uglifyjs-webpack-plugin@~1.1.2: + version "1.1.6" + resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.1.6.tgz#f4ba8449edcf17835c18ba6ae99b9d610857fb19" + dependencies: + cacache "^10.0.1" + find-cache-dir "^1.0.0" + schema-utils "^0.4.2" + serialize-javascript "^1.4.0" + source-map "^0.6.1" + uglify-es "^3.3.4" + webpack-sources "^1.1.0" + worker-farm "^1.5.2" + uid-number@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" @@ -6214,9 +6227,9 @@ webdriver-manager@^12.0.6: semver "^5.3.0" xml2js "^0.4.17" -webpack-concat-plugin@1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/webpack-concat-plugin/-/webpack-concat-plugin-1.4.0.tgz#a6eb3f0082d03c79d8ee2f1518c7f48e44ee12c5" +webpack-concat-plugin@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/webpack-concat-plugin/-/webpack-concat-plugin-1.4.2.tgz#b60bbb626ce5001911809d6e2329fa32f4978a88" dependencies: md5 "^2.2.1" uglify-js "^2.8.29" @@ -6283,15 +6296,22 @@ webpack-sources@^1.0.0, webpack-sources@^1.0.1: source-list-map "^2.0.0" source-map "~0.5.3" +webpack-sources@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + webpack-subresource-integrity@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/webpack-subresource-integrity/-/webpack-subresource-integrity-1.0.1.tgz#1fc09d46497da66e46743a2a51d2cc385b9cb0ed" dependencies: webpack-core "^0.6.8" -webpack@~3.8.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.8.1.tgz#b16968a81100abe61608b0153c9159ef8bb2bd83" +webpack@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.10.0.tgz#5291b875078cf2abf42bdd23afe3f8f96c17d725" dependencies: acorn "^5.0.0" acorn-dynamic-import "^2.0.0" @@ -6366,7 +6386,7 @@ wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" -worker-farm@^1.4.1: +worker-farm@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.5.2.tgz#32b312e5dc3d5d45d79ef44acc2587491cd729ae" dependencies: