ArduCounter: Unterschied zwischen den Versionen

Aus FHEMWiki
Zur Navigation springen Zur Suche springen
Markierungen: mobile edit mobile web edit
(updated to the current version)
Zeile 8: Zeile 8:
|ModOwner=StefanStrobel ({{Link2FU|3960|Forum}} / [[Benutzer:StefanStrobel|Wiki]])
|ModOwner=StefanStrobel ({{Link2FU|3960|Forum}} / [[Benutzer:StefanStrobel|Wiki]])
}}
}}
This module implements an Interface to an Arduino based counter for pulses on any input pin of an Arduino Uno, Nano or similar device like a Jeenode.
This module implements an Interface to an Arduino or ESP8266 based counter for pulses on any input pin of an Arduino Uno, Nano, Jeenode, NodeMCU, Wemos D1 or similar device. The device connects to Fhem either through USB / serial or via tcp if an ESP board is used.
The typical use case is an S0-Interface on an energy meter or water meter.
 
The typical use case is an S0-Interface on an energy meter or water meter, but also reflection light barriers to monitor old ferraris counters are supported


Counters are configured with attributes that define which Arduino pins should count pulses and in which intervals the Arduino board should report the current counts.
Counters are configured with attributes that define which Arduino pins should count pulses and in which intervals the Arduino board should report the current counts.


The Arduino sketch that works with this module uses pin change interrupts so it can efficiently count pulses on all available input pins.
The Arduino sketch that works with this module uses pin change interrupts so it can efficiently count pulses on all available input pins.
The module creates readings for pulse counts, consumption and optionally also a pulse history with pulse lengths and gaps of the last 20 pulses.
The module creates readings for pulse counts, consumption and optionally also a pin history with pulse lengths and gaps of the last pulses.


== Availability ==  
== Availability ==  
Zeile 21: Zeile 22:


== Prerequisites ==
== Prerequisites ==
This module requires Device::SerialPort or Win32::SerialPort module as well as an arduino uno, nano, jeenode or similar device that runs the ArduCounter sketch.
This module requires an Arduino Uno, Nano, Jeenode, NodeMCU, Wemos D1 or similar device based on an Atmel 328p or ESP8266 running the ArduCounter sketch provided with this module
 
In order to flash an arduino board with the corresponding ArduCounter firmware from within Fhem, avrdude needs to be installed.
 
For old ferraris counters an Arduino Uno or Nano or ESP8266 board needs to be connected to a reflection light barrier which consists simply of an infra red photo transistor (connected to A7 on Arduinos and A0 on ESP8266) and an infra red led (connected to D2 on Arduinos and to D6 on ESP8266), both with a resistor in line.
 
This module also requires Device::SerialPort or Win32::SerialPort for communication via serial lines


== Define ==
== Define ==
<pre>define <name> ArduCounter <device></pre>
<pre>define <name> ArduCounter <device></pre>
     
or
<pre>define <name> ArduCounter <ip:port></pre>
 
<device> specifies the serial port to communicate with the Arduino.
<device> specifies the serial port to communicate with the Arduino.
The name of the serial-device depends on your distribution. You can also specify a baudrate if the device name contains the @ character, e.g.: /dev/ttyUSB0@9600
The default baudrate of the firmware is 38400 since Version 1.4 of the sketch.
       
Example:
<pre>define AC ArduCounter /dev/ttyUSB2</pre>


== Configuration of the module ==
<ip:port> specifies the ip address and tcp port to communicate with an esp8266 where port is typically 80.
 
The name of the serial-device depends on your distribution. You can also specify a baudrate for serial connections if the device name contains the @ character, e.g.: /dev/ttyUSB0@38400. The default baudrate of the ArduCounter firmware is 38400 since Version 1.4
 
Examples:
<pre>
define AC ArduCounter /dev/ttyUSB2@38400
define AC ArduCounter 192.168.1.134:80
</pre>
 
== Configuration of ArduCounter digital counters ==
 
Specify the pins where impulses should be counted e.g. as attr AC pinX falling pullup 30
 
The X in pinX can be an Arduino / ESP pin number with or without the letter D e.g. pin4, pinD5, pin6, pinD7 ...


Specify the pins where impulses should be counted e.g. as <pre>attr AC pinX falling pullup 30</pre>
After the pin you can use the keywords falling or rising to define if a logical one / 5V (rising) or a logical zero / 0V (falling) should be treated as pulse.


The X in pinX can be an Arduino pin number with or without the letter D e.g. pin4, pinD5, pin6, pinD7 ...
The optional keyword pullup activates the pullup resistor for the given Pin.


After the pin you can define if the signals to be counted start with rising or falling edges.
The last argument is also optional but recommended and specifies a minimal pulse length in milliseconds.
The optional keyword pullup activates the pullup resistor for the given Arduino Pin.


The last argument is also optional and specifies a minimal pulse length in milliseconds. In this case the first argument (e.g. falling) means that an impulse starts with a falling edge from 1 to 0 and ends when the signal changes back from 0 to 1.
An energy meter with S0 interface is typically connected to GND and an input pin like D4.
The S0 pulse then pulls the input to 0V.
Since the minimal pulse lenght of the s0 interface is specified to be 30ms, the typical configuration for an s0 interface is
attr AC pinX falling pullup 30


== Example: ==
Specifying a minimal pulse length is recommended since it filters bouncing of reed contacts or other noise.


Example:
<pre>
<pre>
define AC ArduCounter /dev/ttyUSB2
define AC ArduCounter /dev/ttyUSB2
attr AC factor 1000
attr AC pulsesPerKWh 1000
attr AC interval 60 300
attr AC interval 60 300
attr AC pinD4 falling pullup 5
attr AC pinD4 falling pullup 5
attr AC pinD5 falling pullup 30
attr AC pinD5 falling pullup 30
attr AC verboseReadings5
attr AC verboseReadingsD5
attr AC pinD6 rising
attr AC pinD6 rising
</pre>
</pre>
       
This defines three counters connected to the pins D4, D5 and D5.
D4 and D5 have their pullup resistors activated and the impulse draws the pins to zero.
For D4 and D5 the arduino measures the time in milliseconds between the falling edge and the rising edge. If this time is longer than the specified 5 or 30 milliseconds then the impulse is counted.
If the time is shorter then this impulse is regarded as noise and added to a separate reject counter.
verboseReadings5 causes the module to create additional readings like the pin history which shows length and gaps between the last pulses.
For pin D6 the arduino does not check pulse lengths and counts every time when the signal changes from 0 to 1.
The ArduCounter sketch which must be loaded on the Arduino or ESP implements this using pin change interrupts, so all avilable input pins can be used, not only the ones that support normal interrupts.
The module has been tested with 14 inputs of an Arduino Uno counting in parallel and pulses as short as 3 milliseconds.
== Configuration of ArduCounter analog counters ==


This defines three counters connected to the pins D4, D5 and D5.
This module and the corresponding sketch can be used to read out old analog ferraris energy counters. Therefore for an Arduino Uno or Nano board (the ESP version does not yet support analog measurements) needs to be connected to a reflection light barrier which consists simply of an infra red photo transistor (connected to A7 on Arduinos and A0 on ESP8266) and an infra red led (connected to D2 on Arduinos and to D6 on ESP8266), both with a resistor in line. The idea comes from Martin Kompf (https://www.kompf.de/tech/emeir.html) and has been adopted for ArduCounter to support old ferraris energy counters.


D4 and D5 have their pullup resistors activated and the impulse draws the pins to zero.
To support this mode, the sketch has to be compiled with analogIR defined.


For D4 and D5 the arduino measures the time in milliseconds between the falling edge and the rising edge. If this time is longer than the specified 5 or 30 milliseconds then the impulse is counted. If the time is shorter then this impulse is regarded as noise and added to a separate reject counter.
The configuration is then similar to the one for digital counters:


verboseReadings5 causes the module to create additional readings like the pulse history which shows length and gaps between the last pulses.
<pre>
define ACF ArduCounter /dev/ttyUSB4
attr ACF analogThresholds 100 110
attr ACF flashCommand avrdude -p atmega328P -b57600 -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2>[LOGFILE]
attr ACF interval 60 300 2 2
attr ACF pinA7 rising 20
attr ACF pulsesPerKWh 75
attr ACF stateFormat {sprintf("%.3f kW", ReadingsVal($name,"powerA7",0))}
</pre>       


For pin D6 the arduino does not check pulse lengths and counts every time when the signal changes from 0 to 1.
To find out the right analog thresholds you can set devVerbose to 20 which will ask the firmware of your conting board to report every analog measurement. The ArduCounter module will count how often each value is reported and you can then query these analog level counts with get levels. After a few turns of the ferraris disc the result of get levels might look like this:


The ArduCounter sketch which must be loaded on the Arduino implements this using pin change interrupts,
<pre>
so all avilable input pins can be used, not only the ones that support normal interrupts.
observed levels from analog input:
94: 21
95: 79
96: 6
97: 2
98: 3
99: 2
100: 2
101: 1
102: 3
105: 2
106: 1
108: 2
109: 1
110: 1
112: 1
113: 3
115: 4
116: 9
117: 14
118: 71
119: 103
120: 118
121: 155
122: 159
123: 143
124: 147
125: 158
126: 198
127: 249
128: 220
129: 230
130: 201
131: 140
132: 147
133: 153
134: 141
135: 119
136: 105
137: 109
138: 114
139: 83
140: 33
141: 14
142: 1     
</pre>     
 
This shows the measured values together with the frequency how often the individual value has been measured. It is obvious that most measurements result in values between 120 and 135, very few values are betweem 96 and 115 and another peak is around the value 95.
It means that the when the red mark of the ferraris disc is under the sensor, the value is around 95 and while the blank disc is under the sensor, the value is typically between 120 and 135. So a good upper threshold would be 120 and a good lower threshold would be for example 96.


The module has been tested with 14 inputs of an Arduino Uno counting in parallel and pulses as short as 3 milliseconds.


== Get-Commands ==
== Get-Commands ==
Zeile 76: Zeile 166:
:send a command to the Arduino board to get current counts.  
:send a command to the Arduino board to get current counts.  
:This is not needed for normal operation but might be useful sometimes for debugging.
:This is not needed for normal operation but might be useful sometimes for debugging.
;levels
:show the count for the measured levels if an analog pin is used to measure e.g. the red mark of a ferraris counter disc.
:This is useful for setting the thresholds for analog measurements.
;history
:shows details regarding all the level changes that the counter device (Arduino or ESP) has detected
:and how they were used (counted or rejected)
:If get history is issued with a pin name (e.g. get history D5) then only the history entries concerning D5 will be shown.
:This information is sent from the device to Fhem when it reports the current count but only if devVerbose is equal or greater than 5.
:The maximum number of lines that the Arducounter module stores in a ring buffer is defined by the attribute maxHist and defaults to 1000.


== Set-Commands ==
== Set-Commands ==
;raw
;raw
:send the value to the Arduino board so you can directly talk to the sketch using its commands.
:send the value to the board so you can directly talk to the sketch using its commands.
:This is not needed for normal operation but might be useful sometimes for debugging
:This is not needed for normal operation but might be useful sometimes for debugging


;flash
;flash
:flashes the ArduCounter firmware ArduCounter.hex from the fhem subdirectory FHEM/firmware
:flashes the ArduCounter firmware ArduCounter.hex from the fhem subdirectory FHEM/firmware onto the device.  
:onto the device. This command needs avrdude to be installed.  
:This command needs avrdude to be installed. The attribute flashCommand specidies how avrdude is called.  
:The attribute flashCommand specifies how avrdude is called.  
:If it is not modifed then the module sets it to avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2>[LOGFILE]
:If it is not modifed then the module sets it to  
:This setting should work for a standard installation and the placeholders are automatically replaced when the command is used.  
:avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2>[LOGFILE]
:So normally there is no need to modify this attribute.
:This setting should work for a standard installation and the placeholders are automatically replaced when the command is used. So normally there is no need to modify this attribute.
:Depending on your specific Arduino board however, you might need to insert -b 57600 in the flash Command.
:(e.g. for an Arduino Nano) ESP boards so far have to be fashed from the Arduino IDE. In a future version flashing over the air sould be supported.


:Depending on your specific Arduino board however, you might need to insert <code>-b 57600</code> in the flash Command.
;reset
:reopens the arduino device and sends a command to it which causes a reinitialize and reset of the counters. Then the module resends the attribute configuration / definition of the pins to the device.
 
;saveConfig
:stores the current interval, analog threshold and pin configuration to be stored in the EEPROM of the counter device
:so it can be retrieved after a reset.
 
;enable
:sets the attribute disable to 0
 
;disable
:sets the attribute disable to 1
 
;reconnect
:closes the tcp connection to an ESP based counter board that is conected via TCP/IP and reopen the connection


;reset
:reopens the arduino device and sends a command to it which causes a reinitialize and reset of the counters.
:Then the module resends the attribute configuration / definition of the pins to the device.


== Supported readings ==
== Supported readings ==
;pinX
The module creates at least the following readings and events for each defined pin:
:the counted total of impulses for pin X


;powerX
;pin.* e.g. pinD4
:the result of (delta count) / (delta time) * factor.
:the current internal count at this pin (internal to the Arduino / ESP device, starts at 0 when the device restarts).
:the number of pulses counted during the last reporting interval diveded by the time between the first pulse and the last pulse in the interval, multiplied by a configurabe factor.
:The name of this reading can be changed with the attribute readingNameCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4


;longX
;long.* e.g. longD5
:long count which keeps on counting up after fhem restarts whereas the pin.* count is only a temporary internal count that starts at 0 when the arduino board starts.
:long count which keeps on counting up after fhem restarts whereas the pin.* count is only a temporary internal count that starts at 0 when the arduino board starts.
:The name of this reading can be changed with the attribute readingNameLongCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4


;interpolatedLongX
;interpolatedLong.*
:like long.* but when the Arduino restarts the potentially missed pulses are interpolated based on the pulse rate before the restart and after the restart.
:like long.* but when the Arduino restarts the potentially missed pulses are interpolated based on the pulse rate before the restart and after the restart.
:The name of this reading can be changed with the attribute readingNameInterpolatedCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4


;rejectX
;calcCounter.*
:counts rejected pulses that are shorter than the specified minimal pulse length.  
:similar to long count which keeps on counting up after fhem restarts but this counter will take the pulses per kWh setting into the :calculation und thus not count pulses but real kWh (or some other unit that is applicable)
:The name of this reading can be changed with the attribute readingNameCalcCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4
 
;reject.*
:counts rejected pulses that are shorter than the specified minimal pulse length.
 
;power.*
:the current calculated power at this pin.
:The name of this reading can be changed with the attribute readingNamePower[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4
 
;pinHistory.*
:shows detailed information of the last pulses. This is only available when a minimal pulse length is specified for this pin. Also the total number of impulses recorded here is limited to 20 for all pins together. The output looks like -36/7:0C, -29/7:1G, -22/8:0C, -14/7:1G, -7/7:0C, 0/7:1G
:The first number is the relative time in milliseconds when the input level changed, followed by the length in milliseconds, the level and the internal action. -36/7:0C for example means that 36 milliseconds before the reporting started, the input changed to 0V, stayed there for 7 milliseconds and this was counted.
 
;countDiff.*
:delta of the current count to the last reported one. This is used together with timeDiff.* to calculate the power consumption.
 
;timeDiff.*
:time difference between the first pulse in the current observation interval and the last one. Used togehter with countDiff to calculate the power consumption.
 
;seq.*
:internal sequence number of the last report from the board to Fhem.


;pinHistoryX
:shows detailed information of the last pulses. This is only available when a minimal pulse length is specified for this pin.
:Also the total number of impulses recorded here is limited to 20 for all pins together.
:The output looks like -36/7:0C, -29/7:1G, -22/8:0C, -14/7:1G, -7/7:0C, 0/7:1G
:The first number is the relative time in milliseconds when the input level changed, followed by the length in milliseconds, the level and the internal action.
:-36/7:0C for example means that 36 milliseconds before the reporting started, the input changed to 0V, stayed there for 7 milliseconds and this was counted.


== Attributes ==
== Attributes ==
;do_not_notify
;do_not_notify
: ...
: ...
Zeile 149: Zeile 281:


;factor  
;factor  
:Define a multiplicator for calculating the power from the impulse count and the time between the first and the last impulse
:Define a multiplicator for calculating the power from the impulse count and the time between the first and the last impulse.
:This attribute is outdated and unintuitive so you should avoid it.
:Instead you should specify the attribute pulsesPerKWh or readingPulsesPerKWh[0-9]+ (where [0-9]+ stands for the pin number).
 
;readingFactor[0-9]+
:Override the factor attribute for this individual pin.
:Just like the attribute factor, this is a rather cumbersome way to specify the pulses per kWh.
:Instaed it is advised to use the attribute pulsesPerKWh or readingPulsesPerKWh[0-9]+ (where [0-9]+ stands for the pin number).
 
;pulsesPerKWh
:specify the number of pulses that the meter is giving out per unit that sould be displayed (e.g. per kWh energy consumed). For many S0 counters this is 1000, for old ferraris counters this is 75 (rounds per kWh).
:Example: attr myCounter pulsesPerKWh 75
 
;readingPulsesPerKWh[0-9]+
:is the same as pulsesPerKWh but specified per pin individually in case you have multiple counters with different settings at the same time
:Example:
:attr myCounter readingPulsesPerKWhA7 75
:attr myCounter readingPulsesPerKWhD4 1000


;readingNameCount[0-9]+  
;readingNameCount[0-9]+  
Zeile 159: Zeile 308:
;readingNameInterpolatedCount[0-9]+  
;readingNameInterpolatedCount[0-9]+  
:Change the name of the counter reading InterpolatedLongX to something more meaningful.
:Change the name of the counter reading InterpolatedLongX to something more meaningful.
;readingNameCalcCount[AD]?[0-9]+
:Change the name of the real unit counter reading CalcCounterX to something more meaningful.
:Example: attr myCounter readingNameCalcCountD4 CounterHaus_kWh


;readingNamePower[0-9]+  
;readingNamePower[0-9]+  
:Change the name of the power reading powerX to something more meaningful.
:Change the name of the power reading powerX to something more meaningful.
;readingFactor[0-9]+
:Override the factor attribute for this individual pin.


;readingStartTime[0-9]+  
;readingStartTime[0-9]+  
Zeile 171: Zeile 321:
;verboseReadings[0-9]+  
;verboseReadings[0-9]+  
:create additional readings: timeDiff, countDiff and lastMsg for each pin
:create additional readings: timeDiff, countDiff and lastMsg for each pin
;devVerbose
:set the verbose level in the counting board. This defaults to 0.
:If the value is >0, then the firmware will echo all commands sent to it by the Fhem module.
:If the value is >=5, then the firmware will report the pin history (assuming that the firmware has been compiled with this feature enabled)
:If the value is >=10, then the firmware will report every level change of a pin
:If the value is >=20, then the firmware will report every analog measurement (assuming that the firmware has been compiled with analog measurements for old ferraris counters or similar).
;maxHist
:specifies how many pin history lines hould be buffered for "get history".
:This attribute defaults to 1000.
;analogThresholds
:this Attribute is necessary when you use an arduino nano with connected reflection light barrier (photo transistor and led) to detect the red mark of an old ferraris energy counter. In this case the firmware uses an upper and lower threshold which can be set here.
:Example: attr myCounter analogThresholds 90 110
:In order to find out the right threshold values you can set devVerbose to 20, wait for several turns of the ferraris disc and then use get levels to see the typical measurements for the red mark and the blank disc.
;flashCommand
:sets the command to call avrdude and flash the onnected arduino with an updated hex file (by default it looks for ArduCounter.hex in the FHEM/firmware subdirectory.
:This attribute contains avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2>[LOGFILE] by default.
:For an Arduino Nano based counter you should add -b 57600 e.g. between the -P and -D options.
:Example: attr myCounter flashCommand avrdude -p atmega328P -c arduino -b 57600 -P [PORT] -D -U flash:w:[HEXFILE] 2>[LOGFILE]
;keepAliveDelay
:defines an interval in which the module sends keepalive messages to a counter device that is conected via tcp.
:This attribute is ignored if the device is connected via serial port.
:If the device doesn't reply within a defined timeout then the module closes and tries to reopen the connection.
:The module tells the device when to expect the next keepalive message and the device will also close the tcp connection if it doesn't see a :keepalive message within the delay multiplied by 3
:The delay defaults to 10 seconds.
:Example: attr myCounter keepAliveDelay 30
;keepAliveTimeout
:defines the timeout when wainting for a keealive reply (see keepAliveDelay) The timeout defaults to 2 seconds.
:Example: attr myCounter keepAliveTimeout 3
;keepAliveRetries
:defines how often sending a keepalive is retried before the connection is closed and reopened.
:It defaults to 2.
:Example: attr myCounter keepAliveRetries 3
;nextOpenDelay
:defines the time that the module waits before retrying to open a disconnected tcp connection.
:This defaults to 60 seconds.
:Example: attr myCounter nextOpenDelay 20
;openTimeout
:defines the timeout after which tcp open gives up trying to establish a connection to the counter device. This timeout defaults to 3 seconds.
:Example: attr myCounter openTimeout 5
;silentReconnect
:if set to 1, then it will set the loglevel for "disconnected" and "reappeared" messages to 4 instead of 3
:Example: attr myCounter silentReconnect 1
;disable
:if set to 1 then the module closes the connection to a counter device.


[[Kategorie:Other Components]]
[[Kategorie:Other Components]]
[[Kategorie:Energieverbrauchsmessung]]
[[Kategorie:Energieverbrauchsmessung]]

Version vom 16. November 2019, 17:07 Uhr

ArduCounter
Zweck / Funktion
Count pulses, calculate time between pulses and convert this to readings for e.g. power consumption of Energy meters
Allgemein
Typ Contrib
Details
Dokumentation Thema
Support (Forum) Sonstiges
Modulname 98_ArduCounter.pm
Ersteller StefanStrobel (Forum / Wiki)
Wichtig: sofern vorhanden, gilt im Zweifel immer die (englische) Beschreibung in der commandref!

This module implements an Interface to an Arduino or ESP8266 based counter for pulses on any input pin of an Arduino Uno, Nano, Jeenode, NodeMCU, Wemos D1 or similar device. The device connects to Fhem either through USB / serial or via tcp if an ESP board is used.

The typical use case is an S0-Interface on an energy meter or water meter, but also reflection light barriers to monitor old ferraris counters are supported

Counters are configured with attributes that define which Arduino pins should count pulses and in which intervals the Arduino board should report the current counts.

The Arduino sketch that works with this module uses pin change interrupts so it can efficiently count pulses on all available input pins. The module creates readings for pulse counts, consumption and optionally also a pin history with pulse lengths and gaps of the last pulses.

Availability

The module has been checked in to the FHEM svn. The corresponding arduino sketch can also be found under contrib in the subdirectory arduino/.

Prerequisites

This module requires an Arduino Uno, Nano, Jeenode, NodeMCU, Wemos D1 or similar device based on an Atmel 328p or ESP8266 running the ArduCounter sketch provided with this module

In order to flash an arduino board with the corresponding ArduCounter firmware from within Fhem, avrdude needs to be installed.

For old ferraris counters an Arduino Uno or Nano or ESP8266 board needs to be connected to a reflection light barrier which consists simply of an infra red photo transistor (connected to A7 on Arduinos and A0 on ESP8266) and an infra red led (connected to D2 on Arduinos and to D6 on ESP8266), both with a resistor in line.

This module also requires Device::SerialPort or Win32::SerialPort for communication via serial lines

Define

define <name> ArduCounter <device>

or

define <name> ArduCounter <ip:port>

<device> specifies the serial port to communicate with the Arduino.

<ip:port> specifies the ip address and tcp port to communicate with an esp8266 where port is typically 80.

The name of the serial-device depends on your distribution. You can also specify a baudrate for serial connections if the device name contains the @ character, e.g.: /dev/ttyUSB0@38400. The default baudrate of the ArduCounter firmware is 38400 since Version 1.4

Examples:

define AC ArduCounter /dev/ttyUSB2@38400
define AC ArduCounter 192.168.1.134:80

Configuration of ArduCounter digital counters

Specify the pins where impulses should be counted e.g. as attr AC pinX falling pullup 30

The X in pinX can be an Arduino / ESP pin number with or without the letter D e.g. pin4, pinD5, pin6, pinD7 ...

After the pin you can use the keywords falling or rising to define if a logical one / 5V (rising) or a logical zero / 0V (falling) should be treated as pulse.

The optional keyword pullup activates the pullup resistor for the given Pin.

The last argument is also optional but recommended and specifies a minimal pulse length in milliseconds.

An energy meter with S0 interface is typically connected to GND and an input pin like D4. The S0 pulse then pulls the input to 0V. Since the minimal pulse lenght of the s0 interface is specified to be 30ms, the typical configuration for an s0 interface is attr AC pinX falling pullup 30

Specifying a minimal pulse length is recommended since it filters bouncing of reed contacts or other noise.

Example:

define AC ArduCounter /dev/ttyUSB2
attr AC pulsesPerKWh 1000
attr AC interval 60 300
attr AC pinD4 falling pullup 5
attr AC pinD5 falling pullup 30
attr AC verboseReadingsD5
attr AC pinD6 rising

This defines three counters connected to the pins D4, D5 and D5. D4 and D5 have their pullup resistors activated and the impulse draws the pins to zero. For D4 and D5 the arduino measures the time in milliseconds between the falling edge and the rising edge. If this time is longer than the specified 5 or 30 milliseconds then the impulse is counted. If the time is shorter then this impulse is regarded as noise and added to a separate reject counter.

verboseReadings5 causes the module to create additional readings like the pin history which shows length and gaps between the last pulses.

For pin D6 the arduino does not check pulse lengths and counts every time when the signal changes from 0 to 1.

The ArduCounter sketch which must be loaded on the Arduino or ESP implements this using pin change interrupts, so all avilable input pins can be used, not only the ones that support normal interrupts. The module has been tested with 14 inputs of an Arduino Uno counting in parallel and pulses as short as 3 milliseconds.

Configuration of ArduCounter analog counters

This module and the corresponding sketch can be used to read out old analog ferraris energy counters. Therefore for an Arduino Uno or Nano board (the ESP version does not yet support analog measurements) needs to be connected to a reflection light barrier which consists simply of an infra red photo transistor (connected to A7 on Arduinos and A0 on ESP8266) and an infra red led (connected to D2 on Arduinos and to D6 on ESP8266), both with a resistor in line. The idea comes from Martin Kompf (https://www.kompf.de/tech/emeir.html) and has been adopted for ArduCounter to support old ferraris energy counters.

To support this mode, the sketch has to be compiled with analogIR defined.

The configuration is then similar to the one for digital counters:

define ACF ArduCounter /dev/ttyUSB4
attr ACF analogThresholds 100 110
attr ACF flashCommand avrdude -p atmega328P -b57600 -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2>[LOGFILE]
attr ACF interval 60 300 2 2
attr ACF pinA7 rising 20
attr ACF pulsesPerKWh 75
attr ACF stateFormat {sprintf("%.3f kW", ReadingsVal($name,"powerA7",0))}

To find out the right analog thresholds you can set devVerbose to 20 which will ask the firmware of your conting board to report every analog measurement. The ArduCounter module will count how often each value is reported and you can then query these analog level counts with get levels. After a few turns of the ferraris disc the result of get levels might look like this:

observed levels from analog input:
94: 21
95: 79
96: 6
97: 2
98: 3
99: 2
100: 2
101: 1
102: 3
105: 2
106: 1
108: 2
109: 1
110: 1
112: 1
113: 3
115: 4
116: 9
117: 14
118: 71
119: 103
120: 118
121: 155
122: 159
123: 143
124: 147
125: 158
126: 198
127: 249
128: 220
129: 230
130: 201
131: 140
132: 147
133: 153
134: 141
135: 119
136: 105
137: 109
138: 114
139: 83
140: 33
141: 14
142: 1      

This shows the measured values together with the frequency how often the individual value has been measured. It is obvious that most measurements result in values between 120 and 135, very few values are betweem 96 and 115 and another peak is around the value 95. It means that the when the red mark of the ferraris disc is under the sensor, the value is around 95 and while the blank disc is under the sensor, the value is typically between 120 and 135. So a good upper threshold would be 120 and a good lower threshold would be for example 96.


Get-Commands

info
send a command to the Arduino board to get current counts.
This is not needed for normal operation but might be useful sometimes for debugging.
levels
show the count for the measured levels if an analog pin is used to measure e.g. the red mark of a ferraris counter disc.
This is useful for setting the thresholds for analog measurements.
history
shows details regarding all the level changes that the counter device (Arduino or ESP) has detected
and how they were used (counted or rejected)
If get history is issued with a pin name (e.g. get history D5) then only the history entries concerning D5 will be shown.
This information is sent from the device to Fhem when it reports the current count but only if devVerbose is equal or greater than 5.
The maximum number of lines that the Arducounter module stores in a ring buffer is defined by the attribute maxHist and defaults to 1000.


Set-Commands

raw
send the value to the board so you can directly talk to the sketch using its commands.
This is not needed for normal operation but might be useful sometimes for debugging
flash
flashes the ArduCounter firmware ArduCounter.hex from the fhem subdirectory FHEM/firmware onto the device.
This command needs avrdude to be installed. The attribute flashCommand specidies how avrdude is called.
If it is not modifed then the module sets it to avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2>[LOGFILE]
This setting should work for a standard installation and the placeholders are automatically replaced when the command is used.
So normally there is no need to modify this attribute.
Depending on your specific Arduino board however, you might need to insert -b 57600 in the flash Command.
(e.g. for an Arduino Nano) ESP boards so far have to be fashed from the Arduino IDE. In a future version flashing over the air sould be supported.
reset
reopens the arduino device and sends a command to it which causes a reinitialize and reset of the counters. Then the module resends the attribute configuration / definition of the pins to the device.
saveConfig
stores the current interval, analog threshold and pin configuration to be stored in the EEPROM of the counter device
so it can be retrieved after a reset.
enable
sets the attribute disable to 0
disable
sets the attribute disable to 1
reconnect
closes the tcp connection to an ESP based counter board that is conected via TCP/IP and reopen the connection


Supported readings

The module creates at least the following readings and events for each defined pin:

pin.* e.g. pinD4
the current internal count at this pin (internal to the Arduino / ESP device, starts at 0 when the device restarts).
The name of this reading can be changed with the attribute readingNameCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4
long.* e.g. longD5
long count which keeps on counting up after fhem restarts whereas the pin.* count is only a temporary internal count that starts at 0 when the arduino board starts.
The name of this reading can be changed with the attribute readingNameLongCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4
interpolatedLong.*
like long.* but when the Arduino restarts the potentially missed pulses are interpolated based on the pulse rate before the restart and after the restart.
The name of this reading can be changed with the attribute readingNameInterpolatedCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4
calcCounter.*
similar to long count which keeps on counting up after fhem restarts but this counter will take the pulses per kWh setting into the :calculation und thus not count pulses but real kWh (or some other unit that is applicable)
The name of this reading can be changed with the attribute readingNameCalcCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4
reject.*
counts rejected pulses that are shorter than the specified minimal pulse length.
power.*
the current calculated power at this pin.
The name of this reading can be changed with the attribute readingNamePower[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4
pinHistory.*
shows detailed information of the last pulses. This is only available when a minimal pulse length is specified for this pin. Also the total number of impulses recorded here is limited to 20 for all pins together. The output looks like -36/7:0C, -29/7:1G, -22/8:0C, -14/7:1G, -7/7:0C, 0/7:1G
The first number is the relative time in milliseconds when the input level changed, followed by the length in milliseconds, the level and the internal action. -36/7:0C for example means that 36 milliseconds before the reporting started, the input changed to 0V, stayed there for 7 milliseconds and this was counted.
countDiff.*
delta of the current count to the last reported one. This is used together with timeDiff.* to calculate the power consumption.
timeDiff.*
time difference between the first pulse in the current observation interval and the last one. Used togehter with countDiff to calculate the power consumption.
seq.*
internal sequence number of the last report from the board to Fhem.


Attributes

do_not_notify
...
pin.*
Define a pin of the Arduino board as input. This attribute expects either rising, falling or change, followed by an optional pullup and an optional number as value.
If a number is specified, the arduino will track rising and falling edges of each impulse and measure the length of a pulse in milliseconds.
The number specified here is the minimal length of a pulse and a pause before a pulse. If one is too small, the pulse is not counted but added to a separate reject counter.
interval normal max min mincout
Defines the parameters that affect the way counting and reporting works.
This Attribute expects at least two and a maximum of four numbers as value.
The first is the normal interval, the second the maximal interval, the third is a minimal interval and the fourth is a minimal pulse count.
In the usual operation mode (when the normal interval is smaller than the maximum interval), the Arduino board just counts and remembers the time between the first impulse and the last impulse for each pin.
After the normal interval is elapsed the Arduino board reports the count and time for those pins where impulses were encountered.
This means that even though the normal interval might be 10 seconds, the reported time difference can be something different because it observed impulses as starting and ending point.
The Power (e.g. for energy meters) is the calculated based of the counted impulses and the time between the first and the last impulse.
For the next interval, the starting time will be the time of the last impulse in the previous reporting period and the time difference will be taken up to the last impulse before the reporting interval has elapsed.
The second, third and fourth numbers (maximum, minimal interval and minimal count) exist for the special case when the pulse frequency is very low and the reporting time is comparatively short.
For example if the normal interval (first number) is 60 seconds and the device counts only one impulse in 90 seconds, the the calculated power reading will jump up and down and will give ugly numbers.
By adjusting the other numbers of this attribute this can be avoided.
In case in the normal interval the observed impulses are encountered in a time difference that is smaller than the third number (minimal interval) or if the number of impulses counted is smaller than the fourth number (minimal count) then the reporting is delayed until the maximum interval has elapsed or the above conditions have changed after another normal interval.
This way the counter will report a higher number of pulses counted and a larger time difference back to fhem.
If this is seems too complicated and you prefer a simple and constant reporting interval, then you can set the normal interval and the mximum interval to the same number. This changes the operation mode of the counter to just count during this normal and maximum interval and report the count. In this case the reported time difference is always the reporting interval and not the measured time between the real impulses.
factor
Define a multiplicator for calculating the power from the impulse count and the time between the first and the last impulse.
This attribute is outdated and unintuitive so you should avoid it.
Instead you should specify the attribute pulsesPerKWh or readingPulsesPerKWh[0-9]+ (where [0-9]+ stands for the pin number).
readingFactor[0-9]+
Override the factor attribute for this individual pin.
Just like the attribute factor, this is a rather cumbersome way to specify the pulses per kWh.
Instaed it is advised to use the attribute pulsesPerKWh or readingPulsesPerKWh[0-9]+ (where [0-9]+ stands for the pin number).
pulsesPerKWh
specify the number of pulses that the meter is giving out per unit that sould be displayed (e.g. per kWh energy consumed). For many S0 counters this is 1000, for old ferraris counters this is 75 (rounds per kWh).
Example: attr myCounter pulsesPerKWh 75
readingPulsesPerKWh[0-9]+
is the same as pulsesPerKWh but specified per pin individually in case you have multiple counters with different settings at the same time
Example:
attr myCounter readingPulsesPerKWhA7 75
attr myCounter readingPulsesPerKWhD4 1000
readingNameCount[0-9]+
Change the name of the counter reading pinX to something more meaningful.
readingNameLongCount[0-9]+
Change the name of the counter reading longX to something more meaningful.
readingNameInterpolatedCount[0-9]+
Change the name of the counter reading InterpolatedLongX to something more meaningful.
readingNameCalcCount[AD]?[0-9]+
Change the name of the real unit counter reading CalcCounterX to something more meaningful.
Example: attr myCounter readingNameCalcCountD4 CounterHaus_kWh
readingNamePower[0-9]+
Change the name of the power reading powerX to something more meaningful.
readingStartTime[0-9]+
Allow the reading time stamp to be set to the beginning of measuring intervals
verboseReadings[0-9]+
create additional readings: timeDiff, countDiff and lastMsg for each pin
devVerbose
set the verbose level in the counting board. This defaults to 0.
If the value is >0, then the firmware will echo all commands sent to it by the Fhem module.
If the value is >=5, then the firmware will report the pin history (assuming that the firmware has been compiled with this feature enabled)
If the value is >=10, then the firmware will report every level change of a pin
If the value is >=20, then the firmware will report every analog measurement (assuming that the firmware has been compiled with analog measurements for old ferraris counters or similar).
maxHist
specifies how many pin history lines hould be buffered for "get history".
This attribute defaults to 1000.
analogThresholds
this Attribute is necessary when you use an arduino nano with connected reflection light barrier (photo transistor and led) to detect the red mark of an old ferraris energy counter. In this case the firmware uses an upper and lower threshold which can be set here.
Example: attr myCounter analogThresholds 90 110
In order to find out the right threshold values you can set devVerbose to 20, wait for several turns of the ferraris disc and then use get levels to see the typical measurements for the red mark and the blank disc.
flashCommand
sets the command to call avrdude and flash the onnected arduino with an updated hex file (by default it looks for ArduCounter.hex in the FHEM/firmware subdirectory.
This attribute contains avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2>[LOGFILE] by default.
For an Arduino Nano based counter you should add -b 57600 e.g. between the -P and -D options.
Example: attr myCounter flashCommand avrdude -p atmega328P -c arduino -b 57600 -P [PORT] -D -U flash:w:[HEXFILE] 2>[LOGFILE]
keepAliveDelay
defines an interval in which the module sends keepalive messages to a counter device that is conected via tcp.
This attribute is ignored if the device is connected via serial port.
If the device doesn't reply within a defined timeout then the module closes and tries to reopen the connection.
The module tells the device when to expect the next keepalive message and the device will also close the tcp connection if it doesn't see a :keepalive message within the delay multiplied by 3
The delay defaults to 10 seconds.
Example: attr myCounter keepAliveDelay 30
keepAliveTimeout
defines the timeout when wainting for a keealive reply (see keepAliveDelay) The timeout defaults to 2 seconds.
Example: attr myCounter keepAliveTimeout 3
keepAliveRetries
defines how often sending a keepalive is retried before the connection is closed and reopened.
It defaults to 2.
Example: attr myCounter keepAliveRetries 3
nextOpenDelay
defines the time that the module waits before retrying to open a disconnected tcp connection.
This defaults to 60 seconds.
Example: attr myCounter nextOpenDelay 20
openTimeout
defines the timeout after which tcp open gives up trying to establish a connection to the counter device. This timeout defaults to 3 seconds.
Example: attr myCounter openTimeout 5
silentReconnect
if set to 1, then it will set the loglevel for "disconnected" and "reappeared" messages to 4 instead of 3
Example: attr myCounter silentReconnect 1
disable
if set to 1 then the module closes the connection to a counter device.