This manual describes connection of float gauge to type S0 IoT convertor. Device can be used for example to indicate flooding of some spaces or for checking water level in tanks.
Used floating gauge have three wires, middle contact (black), contact connected at up position (brown) and contact connected at bottom position of gauge (blue). In case of changing of float gauge, it is important to check correct wiring.
Used solution with three wires have advantage in detection of broken connection to gauge or fault device - if convertor doesn't have input from any contact, it sends error message.
baterry voltage | input status | error detected | |
---|---|---|---|
byte count | 2B | 4B | 4B |
data format | <hex | <int | <int |
payload example | 96 0E | 01 00 00 00 | 00 00 00 00 |
interpretation | voltage in mV | 1- gauge up/0 - gauge down | 1 - error/0-OK |
< - little endian | > - big endian |
Immediately after startup of device, LUA script sets up LoRa communication method and waking up of device at any change of both inputs. Then Convertor switches to sleep mode. If there is not any change on inputs, convetor wakes up every two hours and executes function processInputs
, which checks all inputs and battery voltage. When convertor detects that both float gauge inputs are equal, it checks their states again with delay of 200 ms and increases error counter. In case of reading equal inputs ten times in a row, convertor evaluates this as an error (possible interrupting of wires or faulty float gauge) and sends error state throug LoRaWAN. When acknowledged communiction mode is used, convertor is waiting for acknowledge from LoRaWAN Network Server. After receiving of acknowledge is wake up time set to two hours, if acknowledge is not received, device will wake after two minutes.
When floating gauge changes its state, convertor switches from sleep mode to function onInputChanged
and compares timestamp of last change of stat with actual event. If time between changes is shorter than 10 seconds, change is ignored, which is preventing false positive readings. In other case, function processInputs
is called and convertor works as described in previous paragraph.
-- once in 120 minutes
periodicWakeup = 120
-- join method to use, "OTAA" or "ABP"
joinMethod = "ABP"
-- LoRaWAN port to use
port = 1
-- use confirmed communication
useAcking = 1
-- if no acknowledge, retry after x seconds
noAckRetryAfter = 120
-- retry after 200 miliseconds in case of bad state
errorStateRetryPeriod = 200
-- retry 10 times, then report bad input
errorStateRetryCount = 10
-- ignore onInputChanged if happening faster than once per x ms
ignoreChangeFasterThan = 10000
-- non-inverted direct input, log. 1 when gauge floating high
directInput = 1
-- inverted input of the float gauge, log. 1 when reservoir empty
invertedInput = 2
version = "1.0"
function processInputs()
txbuf = ""
-- get battery voltage
v = api.getBatteryVoltage()
txbuf = txbuf .. pack.pack("<H", v)
directState = api.DIOreadPin(directInput)
invertedState = api.DIOreadPin(invertedInput)
retry = 0
detectedError = 0
-- if equal, then we have error with the sensor
while directState == invertedState do
print(
"Detected bad sensor state, direct = " ..
tostring(directState) .. ", indirect = " .. tostring(invertedState)
)
retry = retry + 1
if retry >= errorStateRetryCount then
-- report an error!
print("Detected error condition " .. tostring(retry) .. " times in row, report it!")
detectedError = 1
break
end
-- delay for next trial
api.delayms(errorStateRetryPeriod)
-- try read again
directState = api.DIOreadPin(directInput)
invertedState = api.DIOreadPin(invertedInput)
end
txbuf = txbuf .. pack.pack("<I2", directState, detectedError)
api.dumpArray(txbuf)
acked = api.loraSend(useAcking, 6000, txbuf, port)
if useAcking == 1 then
if acked >= 0 then
print("Ack received, next message in " .. tostring(periodicWakeup) .. " minutes")
api.wakeUpIn(0, 0, periodicWakeup, 0)
else
print("No ack! Send again in ".. tostring(noAckRetryAfter) .." seconds!")
api.wakeUpIn(0, 0, 0, noAckRetryAfter)
end
else
print("Unconfirmed delivery used, next message in " .. tostring(periodicWakeup) .. " minutes")
api.wakeUpIn(0, 0, periodicWakeup, 0)
end
end
function onWake()
print("Periodic wake up - send a ping, that we are alive")
processInputs()
api.setVar(1, api.getTick()) -- update also the timestamp
end
function onInputChanged(src)
print("Event occured on pin " .. tostring(src))
nowTimestamp = api.getTick()
lastTimestamp = api.getVar(1)
if nowTimestamp < lastTimestamp then
diff = nowTimestamp -- handle overflow of ms tick counter
else
diff = nowTimestamp - lastTimestamp
end
if diff > ignoreChangeFasterThan then
api.setVar(1, nowTimestamp)
processInputs()
else
print("Too fast input change (time difference = " .. tostring(diff) .. " ms), drop!")
end
end
function onStartup()
print("Starting up Lua VM...")
print("Float Gauge script ver. " .. version)
print("Switch to " .. joinMethod .. " activation")
api.loraSetup("ACTIVATION", joinMethod)
print(
"Set input " ..
tostring(directInput) .. " and " .. tostring(invertedInput) .. " to rising/falling edge event source"
)
api.DIOwaitForEvent(directInput, 3)
api.DIOwaitForEvent(invertedInput, 3)
api.setVar(1, 0) -- initial value for "lastTimestamp" in ms
end