Skip to content

Commit

Permalink
Merge remote-tracking branch 'rail4earth/main' into main_server
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolas-f committed Jun 25, 2024
2 parents feccbc0 + 594c78b commit 4684e68
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 63 deletions.
68 changes: 32 additions & 36 deletions services/pixljs_alert/pixljs_ble.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// force timezone to UTC+0200
const CODE_VERSION=1;
const CODE_VERSION=3;
E.setTimeZone(2);
const BUZZING_TIME = 60000; // buzzer time ms
const RESET_NO_ANSWER = 60000;
Expand All @@ -24,7 +24,6 @@ var rssi = -100;
let lastSeen = Date(0);
const MODE_SWITCH_MILLI = 2000;
const TIMEOUT_RPI = 15000;
var button_watch = [0, 0, 0, 0];
var timeout_switch = 0;
var timeout_buzzer = 0;
var timeout_reset = 0;
Expand Down Expand Up @@ -55,37 +54,28 @@ Graphics.prototype.setFontPixeloidSans = function(scale) {
g.setFontPixeloidSans(1);

function disableButtons() {
for (id = 0; id < 4; id++) {
if (button_watch[id] > 0) {
try {
clearWatch(button_watch[id]);
} catch (e) {
//ignore
}
}
button_watch[id] = 0;
}
clearWatch();
}

function watchIdleButtons() {
disableButtons();
setTimeout(e => {
button_watch[0] = setWatch(onPressButtonInstallMode, BTN1, {
setWatch(onPressButtonInstallMode, BTN1, {
repeat: true,
edge: 'both',
debounce: 100
});
button_watch[3] = setWatch(onPressButtonTrainDemo, BTN4, {
setWatch(onPressButtonTrainDemo, BTN4, {
repeat: true,
edge: 'both',
debounce: 100
});
button_watch[2] = setWatch(screenIdle, BTN3, {
setWatch(screenIdle, BTN3, {
repeat: false,
edge: 'falling',
debounce: 10
});
button_watch[1] = setWatch(screenIdle, BTN2, {
setWatch(screenIdle, BTN2, {
repeat: false,
edge: 'falling',
debounce: 10
Expand All @@ -104,13 +94,21 @@ function updateAdvertisement() {
}

function switchStateInstall(newMode) {
if(mode==2) {
formStack.push(JSON.stringify(Object.fromEntries([
["trainCrossingTime", trainCrossingTime],
["timeout", true],
["version", CODE_VERSION],
["answers", Object.fromEntries(currentForm)]
])));
}
mode = newMode;
updateAdvertisement();
if(mode==1) {
Pixl.setLCDPower(true);
LED.write(1);
disableButtons();
button_watch[0] = setWatch(e => {switchStateInstall(0);}, BTN1, {
setWatch(e => {switchStateInstall(0);}, BTN1, {
repeat: false,
debounce: 10
});
Expand Down Expand Up @@ -273,21 +271,21 @@ function screenQuestionB() {
sliderValue = 5;
disableButtons();
questionBDrawScreen();
button_watch[3] = setWatch(e => {
setWatch(e => {
sliderValue = Math.max(0, sliderValue - 1);
questionBDrawScreen();
}, BTN4, {
repeat: true,
edge: 'rising'
});
button_watch[2] = setWatch(e => {
setWatch(e => {
sliderValue = Math.min(10, sliderValue + 1);
questionBDrawScreen();
}, BTN3, {
repeat: true,
edge: 'rising'
});
button_watch[1] = setWatch(e => {
setWatch(e => {
recordAnswer('B', sliderValue);
onQuestionCE(0);
}, BTN2, {
Expand Down Expand Up @@ -327,21 +325,21 @@ function onQuestionCE(index) {
answer_index = parseInt(QUESTIONS[questionIndex][1].length / 2); // default mid answer
disableButtons();
questionCEDrawScreen();
button_watch[3] = setWatch(e => {
setWatch(e => {
answer_index = Math.max(0, answer_index - 1);
questionCEDrawScreen();
}, BTN4, {
repeat: true,
edge: 'rising'
});
button_watch[2] = setWatch(e => {
setWatch(e => {
answer_index = Math.min(QUESTIONS[questionIndex][1].length - 1, answer_index + 1);
questionCEDrawScreen();
}, BTN3, {
repeat: true,
edge: 'rising'
});
button_watch[1] = setWatch(e => {
setWatch(e => {
recordAnswer(String.fromCharCode(67 + questionIndex), QUESTIONS[questionIndex][1][answer_index]);
if (questionIndex + 1 < QUESTIONS.length) {
onQuestionCE(questionIndex + 1);
Expand All @@ -357,6 +355,8 @@ function onQuestionCE(index) {
function endForm() {
formStack.push(JSON.stringify(Object.fromEntries([
["trainCrossingTime", trainCrossingTime],
["timeout", false],
["version", CODE_VERSION],
["answers", Object.fromEntries(currentForm)]
])));
disableButtons();
Expand All @@ -365,12 +365,8 @@ function endForm() {
g.setFontAlign(0.5, 0.5);
g.drawString("Merci pour votre réponse\nAu prochain passage !", g.getWidth() / 2, g.getHeight() / 2);
g.flip();
setTimeout(e => {
Pixl.setLCDPower(false);
LED.write(0);
watchIdleButtons();
}, 5000);
mode = 0;
installResetTimeout()
updateAdvertisement();
}

Expand Down Expand Up @@ -427,12 +423,12 @@ function screenQuestionA() {
g.flip();
disableButtons();
setTimeout(e => {
button_watch[0] = setWatch(onClickSnooze, BTN1, {
setWatch(onClickSnooze, BTN1, {
repeat: false,
edge: 'rising',
debounce: 10
});
button_watch[2] = setWatch(function() {
setWatch(function() {
stopAlarm();
recordAnswer('A', 'non');
onQuestionCE(0);
Expand All @@ -441,7 +437,7 @@ function screenQuestionA() {
edge: 'rising',
debounce: 10
});
button_watch[3] = setWatch(function() {
setWatch(function() {
stopAlarm();
recordAnswer('A', 'oui');
screenQuestionB();
Expand All @@ -455,17 +451,17 @@ function screenQuestionA() {

function screenIdle() {
disableButtons();
button_watch[0] = setWatch(onPressButtonInstallMode, BTN1, {
setWatch(onPressButtonInstallMode, BTN1, {
repeat: true,
edge: 'both',
debounce: 10
});
button_watch[3] = setWatch(onPressButtonTrainDemo, BTN4, {
setWatch(onPressButtonTrainDemo, BTN4, {
repeat: true,
edge: 'both',
debounce: 10
});
button_watch[1] = setWatch(e => {
setWatch(e => {
mode = 2;
currentForm = [];
trainCrossingTime = Date();
Expand All @@ -488,7 +484,7 @@ function screenIdle() {
if(remainSnooze>=3600)
text += parseInt(remainSnooze / 3600) + "h";
text += parseInt((remainSnooze % 3600)/60) + "m de veille.\nRéactiver le boitier>";
button_watch[2] = setWatch(e => {
setWatch(e => {
snooze_time = 0;
screenIdle();
}, BTN3, {
Expand All @@ -497,7 +493,7 @@ function screenIdle() {
debounce: 10
});
} else {
button_watch[2] = setWatch(onClickSnooze, BTN3, {
setWatch(onClickSnooze, BTN3, {
repeat: false,
edge: 'rising',
debounce: 10
Expand Down
76 changes: 63 additions & 13 deletions services/pixljs_alert/zero_ble.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@
import fcntl
import socket
import struct
import re
import base64

UART_SERVICE_UUID = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
UART_RX_CHAR_UUID = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
UART_TX_CHAR_UUID = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
SERVICE_MODE = "0000183b-0000-1000-8000-00805f9b34fb"
SERVICE_ANSWER_SIZE = "0000180a-0000-1000-8000-00805f9b34fb"
SERVICE_VERSION = "0000180b-0000-1000-8000-00805f9b34fb"
FILE_URI = "file://"
logger = logging.getLogger(__name__)

Expand All @@ -38,11 +41,6 @@ def get_hw_address(interface_name):
return ""


def uart_data_received(_: BleakGATTCharacteristic, data: bytearray):
decoded = data.decode('UTF-8')
logger.info(decoded)


def slice_bytes(data: bytes, n: int):
return (data[i:i + n] for i in range(0, len(data), n))

Expand Down Expand Up @@ -95,13 +93,13 @@ def on_found_device(self, device):
self.known_devices[device.address] = time.time()

def stop(self, sig, frame):
# stop main process
self.t.set()
logger.warning("Interrupted by %d, shutting down" % sig)
self.running = False
for k, v in self.known_devices.items():
self.reports[k]["lastSeen"] = time_to_iso(v)
self.socket_out_lost.send_json(self.reports[k])
# stop main process
self.t.set()

def run(self):
self.t.wait(2)
Expand Down Expand Up @@ -171,6 +169,25 @@ def process_message(socket, config, agenda):
return ""


def fetch_script_source_and_version():
uart_commands = []
chunk_size = 1024
source_version = None
with open(os.path.join(os.path.dirname(__file__), "pixljs_ble.js"), "r") as f:
code = f.read()
g = re.search(r'CODE_VERSION=(\d+)', code)
code_bytes = code.encode("iso-8859-1")
if g:
source_version = int(g.group(1))
uart_commands.append("require(\"Storage\").write(\"%s\",atob(\"%s\"),%d,%d);" % (
".bootcde", base64.b64encode(code_bytes[:chunk_size]).decode("UTF8"), 0, len(code_bytes)))
for i in range(chunk_size, len(code_bytes), chunk_size):
uart_commands.append("require(\"Storage\").write(\"%s\",atob(\"%s\"),%d);" % (
".bootcde", base64.b64encode(code_bytes[i:i + chunk_size]).decode("UTF8"), i))
code = "\n".join(uart_commands)+"\nload();\n"
return code.encode("iso-8859-1"), source_version


async def main(config):
# agenda example
agenda = {
Expand All @@ -187,8 +204,11 @@ async def main(config):
socket_out_lost.bind(config.output_address_lost)
ble_tracking = BleTrackingDaemon(socket_out_lost, t)
# json file can be local file ex: "file:///tmp/agenda.json"
agenda_url = "https://dashboard.raw.noise-planet.org/api/agenda/"+get_hw_address("eth0")
agenda_url = "https://dashboard.raw.noise-planet.org/api/agenda/" + get_hw_address("eth0")
agenda_update = AgendaUpdateDaemon(agenda_url, t, agenda)
# fetch expected pixl.js source code
code, source_version = fetch_script_source_and_version()
doing_upgrade = False
# will kill when program end
ble_tracking_thread = Thread(target=ble_tracking.run, daemon=True)
ble_tracking_thread.start()
Expand All @@ -203,13 +223,24 @@ async def main(config):
scan_result = ScanResult(stop_event, ble_tracking)
async with BleakScanner(scan_result.callback) as scanner:
await stop_event.wait()
mode = scan_result.advertising_data.service_data[SERVICE_MODE].decode("ascii")
answer_stack = int.from_bytes(scan_result.advertising_data.service_data[SERVICE_ANSWER_SIZE]
if SERVICE_MODE in scan_result.advertising_data.service_data:
mode = scan_result.advertising_data.service_data[SERVICE_MODE].decode("ascii")
else:
mode = 0
if SERVICE_ANSWER_SIZE in scan_result.advertising_data.service_data:
answer_stack = int.from_bytes(scan_result.advertising_data.service_data[SERVICE_ANSWER_SIZE]
, byteorder="big")
else:
answer_stack = 0
if SERVICE_VERSION in scan_result.advertising_data.service_data:
code_version = int.from_bytes(scan_result.advertising_data.service_data[SERVICE_VERSION]
, byteorder="big")
else:
code_version = 0
if mode == "install":
try:
async with BleakClient(scan_result.device) as client:
await client.start_notify(UART_TX_CHAR_UUID, uart_data_received)
await client.start_notify(UART_TX_CHAR_UUID, scan_result.uart_data_received)
nus = client.services.get_service(UART_SERVICE_UUID)
rx_char = nus.get_characteristic(UART_RX_CHAR_UUID)
now = time.time()
Expand Down Expand Up @@ -255,17 +286,36 @@ async def main(config):
except (BleakError, asyncio.TimeoutError) as e:
logger.error("Send data error", e)
else:
c = process_message(socket, config, agenda)
if source_version == code_version:
c = process_message(socket, config, agenda)
else:
c = code
doing_upgrade = True
print("Sending new version of Pixl.js source code to %s" %
scan_result.device.address)
tries = 0
while c:
try:
async with BleakClient(scan_result.device) as client:
await client.start_notify(UART_TX_CHAR_UUID, uart_data_received)
await client.start_notify(UART_TX_CHAR_UUID, scan_result.uart_data_received)
nus = client.services.get_service(UART_SERVICE_UUID)
rx_char = nus.get_characteristic(UART_RX_CHAR_UUID)
for buffer in slice_bytes(c, rx_char.max_write_without_response_size):
await client.write_gatt_char(rx_char, buffer, False)
# wait for end transfer
await asyncio.sleep(0.05)
while time.time() - scan_result.received_data_time < 0.1:
await asyncio.sleep(0.05)
c = ""
try:
output = scan_result.received_data.getvalue().decode("iso-8859-1")
scan_result.received_data = io.BytesIO()
print(output)
except UnicodeDecodeError as e:
pass
if doing_upgrade:
await asyncio.sleep(10.0)
doing_upgrade = False
except (BleakError, asyncio.TimeoutError) as e:
tries += 1
logger.error("Send data error", e)
Expand Down
2 changes: 1 addition & 1 deletion services/rpi_systemd/zerogps.service
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Requires=gpsd.service

[Service]
Type=simple
ExecStart= /usr/bin/python3.9 -u /home/pi/noisesensor/services/telit/zero_location.py --push_interval 1800 -v --check_ip 194.187.168.100 --device /dev/serial/by-id/usb-Android_LE910C4-EU_0123456789ABCDEF-if05-port0
ExecStart= /usr/bin/python3.9 -u /home/pi/noisesensor/services/telit/zero_location.py --push_interval 1800 -v --check_ip 89.84.1.186 --device /dev/serial/by-id/usb-Android_LE910C4-EU_0123456789ABCDEF-if05-port0
WorkingDirectory=/home/pi/noisesensor/
Restart=always
RestartSec=5s
Expand Down
4 changes: 2 additions & 2 deletions services/rpi_systemd/zerotrigger_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"trigger_tags": ["Train", "Rail transport", "Railroad car, train wagon"],
"trigger_thresholds": [0.1, 0.1, 0.1],
"order_thresholds": [6, 6, 6],
"min_leq": 30.0,
"min_leq": 0,
"total_length": 60.0,
"cached_length": 30.0,
"sample_rate": 48000,
Expand All @@ -21,7 +21,7 @@
"yamnet_cutoff_frequency": 0,
"yamnet_max_gain": 24.0,
"yamnet_window_time": 5.0,
"sensitivity": -28.34,
"sensitivity": -42.87,
"delay_print_samples": 300,
"add_spectrogram": false,
"verbose": false
Expand Down
Loading

0 comments on commit 4684e68

Please sign in to comment.