Skip to content

Commit

Permalink
[tacmi] CoE communication: added thing config parameter 'persistInter…
Browse files Browse the repository at this point in the history
…val' to configure behavour of the integrated persistence service

Signed-off-by: Christian Niessner <[email protected]>
  • Loading branch information
marvkis committed Aug 9, 2020
1 parent 227a746 commit 58ba9a6
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 21 deletions.
20 changes: 16 additions & 4 deletions bundles/org.openhab.binding.tacmi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,22 @@ The _TA C.M.I. CoE Connection_ has to be manually configured.

This thing reflects a connection to a node behind a specific C.M.I.. This node could be every CAN-Capable device from TA which allows to define an CAN-Input.

| Parameter Label | Parameter ID | Description | Accepted values |
|-------------------------|--------------|---------------------------------------------------------------------------------------------------------------|------------------------|
| C.M.I. IP Address | host | Host name or IP address of the C.M.I | host name or ip |
| Node | node | The CoE / CAN Node number openHAB should represent | 1-64 |
| Parameter Label | Parameter ID | Description | Accepted values |
|-------------------------|-----------------|---------------------------------------------------------------------------------------------------------------|------------------------|
| C.M.I. IP Address | host | Host name or IP address of the C.M.I | host name or ip |
| Node | node | The CoE / CAN Node number openHAB should represent | 1-64 |
| Persistence Interval | persistInterval | Mode (-1: during shutdown only; 0: disabled) and interval (in s) for persisting thing states | -1 - 3600; 0: disabled (default); -1: during binding shutdown only; >0: interval in seconds |

A few words to the Persistence Interval:
You have to enable / set it properly when send values from OH -> TA C.M.I. and the value are ciritical for the TA's programming.
As you might already have taken notice when studing the TA's manual, there are always a multpile CoE-values updated withinin a single CoE-message.
This is a design decision made bei TA.
But this also means for CoE-Messages from OH to TA C.M.I. we have to send multiple values at once.
But due to OH's design there is no default restore of previous values out of the box.
This binding implements a own persistance mechanism to save the last known values to have them available after startup of the binding, so we could provide consistent values to TA.
But as most installations are running on Flash-Cards with limitied write cycles, this feature is disabled by default and you have to enable it when needed.
When it is disabled, the binding will send out updates when _output thing cahnnels_ are updated, but 'zero out' all other output channels where the binding dosn't have a valid value yet.
Beside the persistence service, you also have the option to use _CoE Value Validation_ on the TA side to detect invalid values or just to use only every 4th analog and 16th digital channel if this is enough for you.

The thing has no channels by default - they have to be added manually matching the configured inputs / outputs for the related CAN Node. Digital and Analog channels are supported. Please read TA's documentation related to the CAN-protocol - multiple analog (4) and digital (16) channels are combined so please be aware of this design limitation.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,9 @@ public class TACmiConfiguration {
* CoE / CAN node ID we are representing
*/
public int node;

/**
* this identifies the persistence mode / interval
*/
public int persistInterval = 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ private void initializeDetached() {
// this automatically restores persisted states...
this.stateCacheUtils = new StateCacheUtils(
new File(STATE_CACHE_BASE + getThing().getUID().getAsString().replace(':', '_') + ".json"),
this.podDatas.values());
this.podDatas.values(), config.persistInterval);

final Bridge br = getBridge();
final TACmiCoEBridgeHandler bridge = br == null ? null : (TACmiCoEBridgeHandler) br.getHandler();
Expand Down Expand Up @@ -283,7 +283,7 @@ public void dispose() {
@Nullable
final StateCacheUtils scu = this.stateCacheUtils;
if (scu != null) {
scu.persistStates(podDatas.values());
scu.persistStates(podDatas.values(), true);
}
super.dispose();
}
Expand Down Expand Up @@ -358,7 +358,7 @@ public void checkForTimeout() {
}
final StateCacheUtils scu = this.stateCacheUtils;
if (scu != null) {
scu.persistStates(podDatas.values());
scu.persistStates(podDatas.values(), false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
Expand Down Expand Up @@ -43,9 +44,12 @@ public class StateCacheUtils {
// pretty print
final Gson gson = new GsonBuilder().setPrettyPrinting().create();
final File stateCacheFile;
private final int persistInterval;
private long lastPersistTS;

public StateCacheUtils(final File file, final Collection<@Nullable PodData> podDatas) {
public StateCacheUtils(final File file, final Collection<@Nullable PodData> podDatas, int persistInterval) {
this.stateCacheFile = file;
this.persistInterval = persistInterval;
if (this.stateCacheFile.exists()) {
FileReader fr = null;
try {
Expand Down Expand Up @@ -87,26 +91,40 @@ public StateCacheUtils(final File file, final Collection<@Nullable PodData> podD
} catch (final Exception t) {
logger.warn("Restore of state file {} failed: {}", this.stateCacheFile, t.getMessage(), t);
} finally {
if (fr != null)
if (fr != null) {
try {
fr.close();
} catch (final Exception t) {
// ignore...
}
}
}

}
}

public void persistStates(final Collection<@Nullable PodData> data) {
public void persistStates(final Collection<@Nullable PodData> data, boolean isShutdown) {
try {
boolean dirty = false;
if (this.persistInterval == 0 || (this.persistInterval == -1 && !isShutdown)) {
return;
}

long currentTS = System.currentTimeMillis();

if (!isShutdown && (currentTS - this.lastPersistTS) / 1000 < this.persistInterval) {
// persist interval hasn't passed yet...
return;
}
// we persist on shutdown...
boolean dirty = isShutdown ? true : false;
for (final PodData pd : data) {
if (pd != null && pd.message != null && pd.dirty)
if (pd != null && pd.message != null && pd.dirty) {
dirty = true;
}
}
if (!dirty)
if (!dirty) {
return;
}

// we have to persist - transfer state to json structure...
final StateCache sc = new StateCache();
Expand Down Expand Up @@ -135,13 +153,15 @@ public void persistStates(final Collection<@Nullable PodData> data) {

final String json = gson.toJson(sc);

if (!this.stateCacheFile.getParentFile().exists())
if (!this.stateCacheFile.getParentFile().exists()) {
this.stateCacheFile.getParentFile().mkdirs();
}

final FileWriter fw = new FileWriter(this.stateCacheFile);
fw.write(json);
fw.close();
} catch (final Exception t) {
this.lastPersistTS = currentTS;
} catch (final IOException t) {
logger.warn("Persistance of state file {} failed: {}", this.stateCacheFile, t.getMessage(), t);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<!-- Sample Thing Type -->
<thing-type id="cmi" extensible="coe-digital-in,coe-digital-out,coe-analog-in,coe-analog-out">
<supported-bridge-type-refs>
<bridge-type-ref id="coe-bridge"/>
<bridge-type-ref id="coe-bridge" />
</supported-bridge-type-refs>

<label>TA C.M.I. CoE Connection</label>
Expand All @@ -23,6 +23,12 @@
<label>Node</label>
<description>The CoE / CAN Node number openHAB should represent</description>
</parameter>
<parameter name="persistInterval" type="integer" min="-1" max="3600" required="false">
<label>Persistence Interval</label>
<description>Mode (-1: during shutdown only; 0: disabled) and interval (in s) for persisting thing states</description>
<default>0</default>
<advanced>true</advanced>
</parameter>
</config-description>

</thing-type>
Expand All @@ -32,7 +38,7 @@
<item-type>Switch</item-type>
<label>Digital Input (C.M.I. -> OH)</label>
<description>A digital channel sent from C.M.I. to openHAB</description>
<state readOnly="true"/>
<state readOnly="true" />
<config-description>
<parameter name="output" type="integer" min="1" max="32" required="true">
<label>Output</label>
Expand All @@ -56,7 +62,7 @@
<item-type>Number</item-type>
<label>Analog Input Channel (C.M.I. -> OH)</label>
<description>A Analog Channel received from the C.M.I.</description>
<state readOnly="true"/>
<state readOnly="true" />
<config-description>
<parameter name="output" type="integer" min="1" max="32" required="true">
<label>Output</label>
Expand Down Expand Up @@ -142,7 +148,7 @@
<item-type>Switch</item-type>
<label>Switch State (Read-Only)</label>
<description>An On/Off state read from C.M.I.</description>
<state readOnly="true"/>
<state readOnly="true" />
</channel-type>
<channel-type id="schema-switch-rw">
<item-type>Switch</item-type>
Expand All @@ -153,12 +159,12 @@
<item-type>Number</item-type>
<label>Value</label>
<description>A numeric value read from C.M.I.</description>
<state readOnly="true"/>
<state readOnly="true" />
</channel-type>
<channel-type id="schema-state-ro">
<item-type>String</item-type>
<label>Value</label>
<description>A state value read from C.M.I.</description>
<state readOnly="true"/>
<state readOnly="true" />
</channel-type>
</thing:thing-descriptions>

0 comments on commit 58ba9a6

Please sign in to comment.