pxt-calliope/tests/wg-flood-monitor.ts

166 lines
5.2 KiB
TypeScript

let sensorType: string
// ANALOG or TILT
sensorType = "TILT"
while (true) {
// splash screen (flood monitor)
basic.showLeds(`
# # # . .
# . . . .
# # . # .
# . . # .
# . . # #
`)
while (true) {
if (input.buttonIsPressed(Button.A)) {
// test that the sensor works
testMode()
break
} else if (input.buttonIsPressed(Button.B)) {
// run the real flood monitor
floodMonitor()
break
} else {
basic.pause(100)
}
}
}
/**
* test mode - test that the monitor and buzzer work
* no filtering in this mode, direct screen update
*/
function testMode() {
basic.showLeds(`
# # # # #
. . # . .
. . # . .
. . # . .
. . # . .
`)
waitNoButtons()
let img = images.createImage(`
. . . . . . . . . . . . . . . . . . . . # # # # #
. . . . . . . . . . . . . . . # # # # # . . . . .
. . . . . . . . . . # # # # # . . . . . . . . . .
. . . . . # # # # # . . . . . . . . . . . . . . .
# # # # # . . . . . . . . . . . . . . . . . . . .
`)
while (!input.buttonIsPressed(Button.A)) {
// Show live reading on display
let value = readSensor()
img.showImage(value * 5)
// Turn beeper on only if maximum value seen
if (value >= 4) {
pins.digitalWritePin(DigitalPin.P1, 1)
} else {
pins.digitalWritePin(DigitalPin.P1, 0)
}
basic.pause(50)
}
waitNoButtons()
}
function floodMonitor() {
basic.showLeds(`
# . . . #
# # . # #
# . # . #
# . . . #
# . . . #
`)
waitNoButtons()
let line = images.createImage(`
. . . . . . . . . . . . . . . . . . . . # # # # #
. . . . . . . . . . . . . . . # # # # # . . . . .
. . . . . . . . . . # # # # # . . . . . . . . . .
. . . . . # # # # # . . . . . . . . . . . . . . .
# # # # # . . . . . . . . . . . . . . . . . . . .
`)
let state = "SAFE"
let averagedValue = 0
while (!input.buttonIsPressed(Button.A)) {
let value = readSensor()
// Apply some 'lag' filtering to the value, so that 'bobbing' doesn't set off alarm
// i.e. to go from 0 to 4 takes 4 times round the loop
if (value > averagedValue) {
// On the way up, changes in reading are slowed down
averagedValue = averagedValue + 1
} else if (value < averagedValue) {
// On the way down, changes in reading happen immediately
averagedValue = value
}
// Work out what to do based on the averaged value (non bobbing value)
if (state == "SAFE") {
if (averagedValue >= 4) {
pins.digitalWritePin(DigitalPin.P1, 1)
state = "ALARMING"
} else {
// Display raw value as a line
line.showImage(value * 5)
// fill in based on averaged value (long term reading)
for (let i = 0; i < averagedValue; i++) {
led.plot(2, 4 - i)
}
}
} else if (state == "ALARMING") {
if (input.buttonIsPressed(Button.B)) {
pins.digitalWritePin(DigitalPin.P1, 0)
state = "SAFE"
} else {
basic.showAnimation(`
# # # # # . . . . .
# # # # # . . . . .
# # # # # . . . . .
# # # # # . . . . .
# # # # # . . . . .
`, 400)
}
}
basic.pause(300)
}
waitNoButtons()
}
/**
* Read a value 0,1,2,3,4 from either ANALOG or TILT
*/
function readSensor(): number {
let value = 0
// Produce a sensor value in range 0..1023
if (sensorType == "ANALOG") {
// Input range is 0..1023
value = pins.analogReadPin(AnalogPin.P0)
} else if (sensorType == "TILT") {
// Input range is -1024 (pads highest)..1023 (pads lowest)
value = input.acceleration(Dimension.Y)
// Emulator sometimes returns out of range values, so clamp to expected range
value = Math.clamp(-1024, 1023, value)
// Convert to an entirely positive range from 0 pads full up to 2047 pads full down
// (hinged at the 'eyes' end)
value = value + 1024
// Invert the direction, so that "pads up" is largest, "pads down" is smallest
value = 2047 - value
// We want the same range as the analog, so halve the range
value = value / 2
}
// 5 possible values (0,1,2,3,4) based on sensible thresholds
// We do this by thresholds, so that we have more control over the 5 levels
if (value < 200) {
return 0
} else if (value < 400) {
return 1
} else if (value < 600) {
return 2
} else if (value < 800) {
return 3
}
return 4
}
function waitNoButtons() {
while (input.buttonIsPressed(Button.A) || input.buttonIsPressed(Button.B)) {
basic.pause(100)
}
}