-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathread_meter.bash
executable file
·272 lines (242 loc) · 9.53 KB
/
read_meter.bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
#!/bin/bash
#h-------------------------------------------------------------------------------
#h
#h Name: read_meter.bash
#h Type: Linux shell script
#h Purpose: in an infinite loop:
#h reads value fom electric meter via infrared interface (optical
#h interface) and forwards it to a round-robin database and
#h additionally to a Z-Way virtual device
#h
#h Installation:
#h Project:
#h Usage: 1. start manually:
#h cd <path>
#h ./read_meter.bash >/dev/null 2>&1 &
#h 2. run with cron:
#h crontab -e
#h and enter:
#h @reboot <path>/read_meter.bash >/dev/null 2>&1
#h Result:
#h Examples:
#h Outline:
#h Resources: stty, curl
#h Platforms: Linux
#h Authors: peb piet66
#h Version: V3.2.0 2024-04-06/peb
#v History: V1.0.0 2022-05-31/peb first version
#v V1.3.0 2022-11-20/peb [+]STORE_COMMAND
#v V2.0.0 2022-11-20/peb [*]some refactoring
#v V2.1.0 2023-03-21/peb [*]baud reset in case of missing !
#v V3.1.0 2023-05-31/peb [+]enhance settings file
#v generalization for protocol modes A-D
#h Copyright: (C) piet66 2022
#h License: MIT
#h
#h-------------------------------------------------------------------------------
MODULE='read_meter.bash';
VERSION='V3.2.0'
WRITTEN='2024-04-06/peb'
DIR=`dirname $0`
cd $DIR
PWD=`pwd`
SN=`basename $0`
[ "$DIR" != "$PWD" ] && exec $PWD/$SN #restart with full path
LOG=$SN.log
date >$LOG
LOG_SLEEP=${SN}_SLEEP.log
LOG_READ=${SN}_READ.log
#b write start message to syslog
#-------------------------------
logger -i "$PWD $SN $VERSION $WRITTEN started."
#b kill all child processes at end
#---------------------------------
trap "pkill -SIGTERM -P $$; exit" SIGINT SIGTERM
#b take settings
#---------------
DISABLE_BAUD_RATE_CHANGEOVER = false
. ./settings >>$LOG 2>&1
NEXT=
if [ ! -c "$DEV" ]
then
mess="serial input IR device $DEV not found, waiting..."
logger -is "$SN $mess" >>$LOG 2>&1
#wait 1 minute after boot till device is ready
sleep 1m
if [ ! -c "$DEV" ]
then
mess="serial input IR device $DEV not found, exit!"
logger -is "$SN $mess" >>$LOG 2>&1
exit 1
fi
fi
#b read rrb parameters
#---------------------
if [ "$STORE_LOCAL_RRD" == true ] || [ "$STORE_REMOTE_RRD" == true ]
then
. ./rrd_info.bash >>$LOG 2>&1
fi
#b functions
#-----------
# -------------------------------------------------------------------------------
# Name: delay
# Purpose: computes sleep time for next request ($sleep_secs)
# -------------------------------------------------------------------------------
function delay() {
currtime=$(date +%s) #current time in seconds
[ "$next_run" == "" ] && next_run=currtime
(( sleep_secs=next_run-currtime )); # delay time in seconds
}
# -------------------------------------------------------------------------------
# Name: compute_rrd_time
# Purpose: computes correct timestamp for rrdtool database
# -------------------------------------------------------------------------------
function compute_rrd_time() {
step=$STEP
currtime=$(date +%s) #current time in seconds
(( rrd_time=(currtime/step)*step ));
echo "currtime=$currtime"
echo "rrd_time=$rrd_time"
}
# -------------------------------------------------------------------------------
# Name: create_pull_loop
# Purpose: trigger request 6.3.1 in infinite loop
# synchronized with $NEXT and $STEP
# -------------------------------------------------------------------------------
function create_pull_loop() {
echo invoke pull loop
next_run=$NEXT
echo next_run=$next_run
while true
do
delay
echo ''
echo --- next request in $sleep_secs seconds...
[ $sleep_secs -gt 0 ] && sleep $sleep_secs
#in case of wrong baud rate, caused by communication issue:
BAUD=`stty -F $DEV speed`
if [ $BAUD -ne $BAUD_INI ]
then
date >>$LOG_SLEEP
cat $LOG_READ >>$LOG_SLEEP
echo --- current baud rate: $BAUD | tee -a $LOG_SLEEP
BAUD=$BAUD_INI
stty -F $DEV $BAUD
echo --- baud rate set to $BAUD | tee -a $LOG_SLEEP
[ -x "sendEmail.bash" ] && ./sendEmail.bash "baud rate set to $BAUD" &
fi
echo -n -e '/?!\r\n' > $DEV
last_run=$next_run
(( next_run=last_run+STEP ));
done
}
#b commands
#----------
#b set serial interface parameters
#---------------------------------
[ "$IEC_62056_21_MODE" != "D" ] && BAUD_INI=300 #default, except for mode D
#7E1, no flow control, no handshake:
#stty -F $DEV sane
stty -F $DEV $BAUD_INI -parodd cs7 -cstopb parenb -ixoff -crtscts -hupcl -ixon -opost -onlcr -isig -icanon -iexten -echo -echoe -echoctl -echoke
BAUD=$BAUD_INI
#b if no push mode: trigger request 6.3.1 in infinite loop
#---------------------------------------------------------
[ "$IEC_62056_21_MODE" != "D" ] && create_pull_loop $NEXT $STEP &
#b in infinite loop
#------------------
rm -f $LOG_READ
while true
do
#b listening with target baud rate
#---------------------------------
BAUD_curr=`stty -F $DEV speed`
[ $BAUD_curr -ne $BAUD ] && stty -F $DEV $BAUD
echo listening to $DEV with `stty -F $DEV speed` baud... | tee -a $LOG_READ
count_secs=-1 #for push mode
while read line
do
[ "$line" == "" ] && continue
echo "$line" | tee $LOG_READ
case "$line" in
#b ident message 6.3.2
#---------------------
/*)
val180=
if [ "$IEC_62056_21_MODE" == "D" ]
then
count_secs=$(($count_secs+1))
[ $count_secs -gt $STEP ] && count_secs=0
fi
V=0 # Protocol control character (see 6.4.5.2), 0=normal protocol
Z=0 # Baud rate identification, 0=300, 4=4800, 5=9600
Y=0 # Mode control character (see 6.4.5.3), 0=data readout
# /xxxZ: Z=possible baud rate
Z=${line:4:1} #take 5th character from line
if [ "$IEC_62056_21_MODE" == "B" ]
then
Z=`printf '%d' "'$Z"`; Z=$(($Z-65)) #character to number
fi
if [ "$IEC_62056_21_MODE" == "C" ] #send ack 6.3.3 with baud switchover
then
[ "$DISABLE_BAUD_RATE_CHANGEOVER" == true ] && Z=0
ACK='\x06'$V$Z$Y
echo $ACK | tee -a $LOG_READ
echo -n -e $ACK'\r\n' > $DEV
fi
(( BAUD_NEW=300*2**Z ))
if [ $BAUD -ne $BAUD_NEW ]
then
# remark: timing problem between ACK and stty -F $DEV $BAUD:
# - switching too fast >> meter doesn't get ACK
# - switching too slow >> response of meter is lost
BAUD=$BAUD_NEW
echo switching to baud rate $BAUD
break
fi
;;
#b OBIS 1.8.0: strip value
#-------------------------
*1.8.0*)
if [ "$IEC_62056_21_MODE" == "D" ]
then
[ $count_secs -ne 0 ] && continue
fi
#parameter expansion:
a="${line#*\(}" #remove first part till '('
val180="${a%\**}" #remove last part from '*' on
if [ "$STORE_ZWAY" == true ]
then
echo ">> ./store_zway.bash ${ZWAY_devices["180"]} $val180"
./store_zway.bash ${ZWAY_devices["180"]} $val180 &
fi
;;
#b end of datablock 6.3.4:
#b store data, break listening and reset baud rate for next request
#------------------------------------------------------------------
!)
if [ "$val180" != "" ] && [ "$STORE_LOCAL_RRD" == true ]
then
compute_rrd_time
val180Wh=${val180/./} #real >>> integer, kWh >>> Wh
values=${val180}:${val180Wh}
echo ">> ./store_rrd_local.bash $rrd_time $values"
./store_rrd_local.bash $rrd_time $values &
fi
if [ "$val180" != "" ] && [ "$STORE_REMOTE_RRD" == true ]
then
compute_rrd_time
val180Wh=${val180/./} #real >>> integer, kWh >>> Wh
values=${val180}:${val180Wh}
echo ">> ./store_rrd_remote.bash $rrd_time $values"
./store_rrd_remote.bash $rrd_time $values &
fi
if [ $BAUD -ne $BAUD_INI ]
then
BAUD=$BAUD_INI
break
fi
;;
esac
done <"$DEV"
echo ''
done