use of io.openems.api.channel.ConfigChannel in project openems by OpenEMS.
the class EdgeWebsocketHandler method config.
/**
* Handle "config" messages
*
* @param jConfig
* @return
*/
private synchronized void config(Role role, JsonObject jMessageId, Optional<ApiWorker> apiWorkerOpt, JsonObject jConfig) {
Optional<String> modeOpt = JsonUtils.getAsOptionalString(jConfig, "mode");
switch(modeOpt.orElse("")) {
case "query":
/*
* Query current config
*/
try {
String language = JsonUtils.getAsString(jConfig, "language");
JsonObject jReplyConfig = Config.getInstance().getJson(ConfigFormat.OPENEMS_UI, role, language);
WebSocketUtils.send(this.websocket, DefaultMessages.configQueryReply(jMessageId, jReplyConfig));
return;
} catch (OpenemsException e) {
WebSocketUtils.sendNotificationOrLogError(this.websocket, jMessageId, LogBehaviour.WRITE_TO_LOG, Notification.UNABLE_TO_READ_CURRENT_CONFIG, e.getMessage());
}
case "update":
/*
* Update thing/channel config
*/
Optional<String> thingIdOpt = JsonUtils.getAsOptionalString(jConfig, "thing");
Optional<String> channelIdOpt = JsonUtils.getAsOptionalString(jConfig, "channel");
try {
String thingId = thingIdOpt.get();
String channelId = channelIdOpt.get();
JsonElement jValue = JsonUtils.getSubElement(jConfig, "value");
Optional<Channel> channelOpt = ThingRepository.getInstance().getChannel(thingId, channelId);
if (channelOpt.isPresent()) {
Channel channel = channelOpt.get();
// check write permissions
channel.assertWriteAllowed(role);
if (channel instanceof ConfigChannel<?>) {
/*
* ConfigChannel
*/
ConfigChannel<?> configChannel = (ConfigChannel<?>) channel;
Object value = ConfigUtils.getConfigObject(configChannel, jValue);
configChannel.updateValue(value, true);
WebSocketUtils.sendNotificationOrLogError(this.websocket, jMessageId, LogBehaviour.WRITE_TO_LOG, Notification.EDGE_CHANNEL_UPDATE_SUCCESS, channel.address() + " => " + jValue);
} else if (channel instanceof WriteChannel<?>) {
/*
* WriteChannel
*/
WriteChannel<?> writeChannel = (WriteChannel<?>) channel;
if (!apiWorkerOpt.isPresent()) {
WebSocketUtils.sendNotificationOrLogError(this.websocket, jMessageId, LogBehaviour.WRITE_TO_LOG, Notification.BACKEND_NOT_ALLOWED, "set " + channel.address() + " => " + jValue);
} else {
ApiWorker apiWorker = apiWorkerOpt.get();
WriteObject writeObject = new WriteJsonObject(jValue).onFirstSuccess(() -> {
WebSocketUtils.sendNotificationOrLogError(this.websocket, jMessageId, LogBehaviour.WRITE_TO_LOG, Notification.EDGE_CHANNEL_UPDATE_SUCCESS, "set " + channel.address() + " => " + jValue);
}).onFirstError((e) -> {
WebSocketUtils.sendNotificationOrLogError(this.websocket, jMessageId, LogBehaviour.WRITE_TO_LOG, Notification.EDGE_CHANNEL_UPDATE_FAILED, "set " + channel.address() + " => " + jValue, e.getMessage());
}).onTimeout(() -> {
WebSocketUtils.sendNotificationOrLogError(this.websocket, jMessageId, LogBehaviour.WRITE_TO_LOG, Notification.EDGE_CHANNEL_UPDATE_TIMEOUT, "set " + channel.address() + " => " + jValue);
});
apiWorker.addValue(writeChannel, writeObject);
}
}
} else {
WebSocketUtils.sendNotificationOrLogError(this.websocket, jMessageId, LogBehaviour.WRITE_TO_LOG, Notification.CHANNEL_NOT_FOUND, thingId + "/" + channelId);
}
} catch (NoSuchElementException | OpenemsException e) {
WebSocketUtils.sendNotificationOrLogError(this.websocket, jMessageId, LogBehaviour.WRITE_TO_LOG, Notification.EDGE_CHANNEL_UPDATE_FAILED, thingIdOpt.orElse("UNDEFINED") + "/" + channelIdOpt.orElse("UNDEFINED"), e.getMessage());
}
}
}
use of io.openems.api.channel.ConfigChannel in project openems by OpenEMS.
the class ChannelRegisterMap method setValue.
protected void setValue(MyRegister register, byte b1, byte b2) throws OpenemsException {
int registerNo = register.getRegisterNo();
this.setBuffer[registerNo * 2] = b1;
this.setBuffer[registerNo * 2 + 1] = b2;
// is the buffer full?
for (int i = 0; i < this.setBuffer.length; i++) {
if (this.setBuffer[i] == null) {
// no, it is not full
return;
}
}
// yes, it is full -> parse value to Object
byte[] value = new byte[this.setBuffer.length];
boolean isPositive = true;
for (int i = this.setBuffer.length - 1; i > 0; i -= 2) {
if (((this.setBuffer[i - 1] >>> 8) & 1) != 0) {
// test if the 'negative-bit' is set
isPositive = false;
}
value[i] = this.setBuffer[i];
value[i - 1] = this.setBuffer[i - 1];
}
if (!isPositive) {
// fill leading bytes with 0xFF if the value is negative
for (int i = 0; i < value.length; i++) {
if (value[i] != 0) {
break;
}
value[i] = (byte) 0xff;
}
}
// int bitLength = getBitLength(type);
// System.out.println(bitLength + " - " + bytesToHex(value));
Object valueObj = BitUtils.toObject(this.channelDoc.getTypeOpt().get(), value);
Channel channel = this.getChannel();
if (channel instanceof ConfigChannel<?>) {
// it is a ConfigChannel -> write directly
ConfigChannel<?> configChannel = (ConfigChannel<?>) channel;
configChannel.updateValue(valueObj, true);
log.info("Updated [" + this.channelAddress + "] to [" + valueObj + "] via Modbus/TCP.");
} else if (channel instanceof WriteChannel<?>) {
// it is a WriteChannel -> handle by ApiWorker
WriteChannel<?> writeChannel = (WriteChannel<?>) channel;
WritePOJO writeObject = new WritePOJO(valueObj);
apiWorker.addValue(writeChannel, writeObject);
}
}
use of io.openems.api.channel.ConfigChannel in project openems by OpenEMS.
the class ConfigUtils method getAsJsonElement.
/**
* Converts an object to a JsonElement
*
* @param value
* @return
* @throws NotImplementedException
*/
public static JsonElement getAsJsonElement(Object value, ConfigFormat format, Role role) throws NotImplementedException {
// null
if (value == null) {
return null;
}
// optional
if (value instanceof Optional<?>) {
if (!((Optional<?>) value).isPresent()) {
return null;
} else {
value = ((Optional<?>) value).get();
}
}
try {
/*
* test for simple types
*/
return JsonUtils.getAsJsonElement(value);
} catch (NotImplementedException e) {
;
}
if (value instanceof Thing) {
/*
* type Thing
*/
Thing thing = (Thing) value;
JsonObject j = new JsonObject();
if (format == ConfigFormat.OPENEMS_UI || !thing.id().startsWith("_")) {
// ignore generated id names starting with "_"
j.addProperty("id", thing.id());
j.addProperty("alias", thing.getAlias());
}
// for file-format class is not needed for DeviceNatures
j.addProperty("class", thing.getClass().getCanonicalName());
ThingRepository thingRepository = ThingRepository.getInstance();
for (ConfigChannel<?> channel : thingRepository.getConfigChannels(thing)) {
if (channel.isReadAllowed(role)) {
// check read permissions
JsonElement jChannel = null;
jChannel = ConfigUtils.getAsJsonElement(channel, format, role);
if (jChannel != null) {
j.add(channel.id(), jChannel);
}
}
}
// for Bridge: add 'devices' array of thingIds
if (value instanceof Bridge) {
Bridge bridge = (Bridge) value;
JsonArray jDevices = new JsonArray();
for (Device device : bridge.getDevices()) {
jDevices.add(device.id());
}
j.add("devices", jDevices);
}
return j;
} else if (value instanceof ConfigChannel<?>) {
/*
* type ConfigChannel
*/
ConfigChannel<?> channel = (ConfigChannel<?>) value;
if (!channel.valueOptional().isPresent()) {
// no value set
return null;
} else if (format == ConfigFormat.FILE && channel.getDefaultValue().equals(channel.valueOptional())) {
// default value not changed
return null;
} else {
// recursive call
return ConfigUtils.getAsJsonElement(channel.valueOptional().get(), format, role);
}
} else if (value instanceof ThingMap) {
/*
* ThingMap (we need only id)
*/
return new JsonPrimitive(((ThingMap) value).id());
} else if (value instanceof List<?>) {
/*
* List
*/
JsonArray jArray = new JsonArray();
for (Object v : (List<?>) value) {
jArray.add(ConfigUtils.getAsJsonElement(v, format, role));
}
return jArray;
} else if (value instanceof Set<?>) {
/*
* Set
*/
JsonArray jArray = new JsonArray();
for (Object v : (Set<?>) value) {
jArray.add(ConfigUtils.getAsJsonElement(v, format, role));
}
return jArray;
}
throw new NotImplementedException(//
"Converter for [" + value + "]" + " of type [" + value.getClass().getSimpleName() + //
"]" + " to JSON is not implemented.");
}
use of io.openems.api.channel.ConfigChannel in project openems by OpenEMS.
the class ThingRepository method addThing.
/**
* Add a Thing to the Repository and cache its Channels and other information for later usage.
*
* @param thing
*/
public synchronized void addThing(Thing thing) {
if (thingIds.containsValue(thing)) {
// Thing was already added
return;
}
// Add to thingIds
thingIds.forcePut(thing.id(), thing);
// Add to thingClasses
thingClasses.put(thing.getClass(), thing);
// Add to bridges
if (thing instanceof Bridge) {
bridges.add((Bridge) thing);
}
// Add to schedulers
if (thing instanceof Scheduler) {
schedulers.add((Scheduler) thing);
}
// Add to persistences
if (thing instanceof Persistence) {
persistences.add((Persistence) thing);
}
// Add to queryablePersistences
if (thing instanceof QueryablePersistence) {
queryablePersistences.add((QueryablePersistence) thing);
}
// Add to device natures
if (thing instanceof DeviceNature) {
deviceNatures.add((DeviceNature) thing);
}
// Add Listener
thing.addListener(this);
// Apply channel annotation (this happens now and again after initializing the thing via init()
this.applyChannelAnnotation(thing);
// Add Channels thingConfigChannels
ThingDoc thingDoc = classRepository.getThingDoc(thing.getClass());
for (ChannelDoc channelDoc : thingDoc.getChannelDocs()) {
Member member = channelDoc.getMember();
try {
List<Channel> channels = new ArrayList<>();
java.util.function.Consumer<Channel> addToChannels = (c) -> {
if (c == null) {
// TODO this error is not handled properly
// 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) {
addToChannels.accept(c);
}
} else {
// It's a Method with ReturnType Channel
Channel c = (Channel) ((Method) member).invoke(thing);
addToChannels.accept(c);
if (c instanceof ThingStateChannels) {
ThingStateChannels tsc = (ThingStateChannels) c;
for (ThingStateChannel fc : tsc.getFaultChannels()) {
addToChannels.accept(fc);
}
for (ThingStateChannel wc : tsc.getWarningChannels()) {
addToChannels.accept(wc);
}
}
}
} else if (member instanceof Field) {
// It's a Field with Type Channel
Channel c = (Channel) ((Field) member).get(thing);
addToChannels.accept(c);
} else {
continue;
}
if (channels.isEmpty()) {
continue;
}
for (Channel channel : channels) {
// Add Channel to thingChannels
thingChannels.put(thing, channel.id(), channel);
if (channel instanceof ConfigChannel) {
// Add Channel to configChannels
thingConfigChannels.put(thing, (ConfigChannel<?>) channel);
}
}
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
log.warn("Unable to add Channel. Member [" + member.getName() + "]", e);
}
}
for (ThingsChangedListener listener : thingListeners) {
listener.thingChanged(thing, Action.ADD);
}
}
use of io.openems.api.channel.ConfigChannel in project openems by OpenEMS.
the class ThingRepository method thingChannelsUpdated.
@Override
public void thingChannelsUpdated(Thing thing) {
// remove Channels from thingChannels, thingWriteChannels
Databus databus = Databus.getInstance();
Set<Entry<String, Channel>> thingRow = thingChannels.row(thing).entrySet();
Iterator<Entry<String, Channel>> i = thingRow.iterator();
while (i.hasNext()) {
Entry<String, Channel> thingChannel = i.next();
if (!(thingChannel.getValue() instanceof ConfigChannel)) {
thingChannel.getValue().removeChangeListener(databus);
thingChannel.getValue().removeUpdateListener(databus);
i.remove();
}
}
thingWriteChannels.removeAll(thing);
// Add Channels to thingChannels, thingConfigChannels and thingWriteChannels
ThingDoc thingDoc = classRepository.getThingDoc(thing.getClass());
for (ChannelDoc channelDoc : thingDoc.getChannelDocs()) {
Member member = channelDoc.getMember();
try {
List<Channel> channels = new ArrayList<>();
boolean ignoreEmpty = false;
if (member instanceof Method) {
if (((Method) member).getReturnType().isArray()) {
// ignore e.g. if getFaultChannels is returning an empty array
ignoreEmpty = true;
Channel[] ch = (Channel[]) ((Method) member).invoke(thing);
for (Channel c : ch) {
channels.add(c);
}
} else {
// It's a Method with ReturnType Channel
channels.add((Channel) ((Method) member).invoke(thing));
}
} else if (member instanceof Field) {
// It's a Field with Type Channel
channels.add((Channel) ((Field) member).get(thing));
} else {
continue;
}
if (!ignoreEmpty && channels.isEmpty()) {
log.warn("Channel is returning null! Thing [" + thing.id() + "], Member [" + member.getName() + "]");
continue;
}
for (Channel channel : channels) {
if (channel != null) {
// Add Channel to thingChannels
thingChannels.put(thing, channel.id(), channel);
// Add Channel to writeChannels
if (channel instanceof WriteChannel) {
thingWriteChannels.put(thing, (WriteChannel<?>) channel);
}
// Register Databus as listener
if (channel instanceof ReadChannel) {
((ReadChannel<?>) channel).addUpdateListener(databus);
((ReadChannel<?>) channel).addChangeListener(databus);
}
}
}
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
log.warn("Unable to add Channel. Member [" + member.getName() + "]", e);
}
}
}
Aggregations