Menticol
Active Member
Hello ETO guys:
I'm working on a little alarm system for my workshop, using a Raspberry Pi Pico W, a PIR sensor, and a reed switch sensor. The distance between the Pi and these sensors would be 15 meters at most, connected with twisted pair cable.
With the help of AI (denying its involvement would be a gross lie) I I was able to generate a working code that connects to the Wi Fi network, can be armed / disarmed via inbound telegram message, and also reports the sensor triggering via an outgoing telegram message.
First question: This design only reads Open: Normal / Shorted to ground: Alarm. The proper way must be: x resistance value (provided by an 5.6k EOL resistor): Normal / Open or Shorted to Ground, Alarm. My first thought was switching to analog inputs, installing the cable in the workshop, measuring its resistance on ohms, and program that into the Micro. But that's very inconvenient! How is a commercial system able to work with different installations and lengths of wire, without reprogramming anything?
Second question: A long cable from the sensors to the Pico is vulnerable to electromagnetic interference, and why not sabotage (a simple taser would fry the Microcontroller). How is this problem addressed on a commercial system? I was thinking an optoisolator, but that would collide with the previous question.
As always, thank you very much for your time
Below is my code, in case the reader wants to implement a similar system at his/her home:
I'm working on a little alarm system for my workshop, using a Raspberry Pi Pico W, a PIR sensor, and a reed switch sensor. The distance between the Pi and these sensors would be 15 meters at most, connected with twisted pair cable.
With the help of AI (denying its involvement would be a gross lie) I I was able to generate a working code that connects to the Wi Fi network, can be armed / disarmed via inbound telegram message, and also reports the sensor triggering via an outgoing telegram message.
First question: This design only reads Open: Normal / Shorted to ground: Alarm. The proper way must be: x resistance value (provided by an 5.6k EOL resistor): Normal / Open or Shorted to Ground, Alarm. My first thought was switching to analog inputs, installing the cable in the workshop, measuring its resistance on ohms, and program that into the Micro. But that's very inconvenient! How is a commercial system able to work with different installations and lengths of wire, without reprogramming anything?
Second question: A long cable from the sensors to the Pico is vulnerable to electromagnetic interference, and why not sabotage (a simple taser would fry the Microcontroller). How is this problem addressed on a commercial system? I was thinking an optoisolator, but that would collide with the previous question.
As always, thank you very much for your time
Below is my code, in case the reader wants to implement a similar system at his/her home:
Python:
WIFI_SSID = "PEQLL"
WIFI_PASSWORD = "password"
TELEGRAM_BOT_TOKEN = "dummy"
ALLOWED_USERS = ["-dummy", "dummy"]
TELEGRAM_MAIN_CHAT_ID = ALLOWED_USERS[0]
armed_status = False
import network
import urequests
import time
import machine
import json
IMMEDIATE_ALARM_PINS = [15, 14, 13]
trigger_pins = []
for pin_num in IMMEDIATE_ALARM_PINS:
trigger_pins.append(machine.Pin(pin_num, machine.Pin.IN, machine.Pin.PULL_UP))
last_update_id = None
def connect_wifi(ssid, password):
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
try:
if not wlan.isconnected():
print('Connecting to Wi-Fi...')
wlan.connect(ssid, password)
max_wait = 10
while max_wait > 0:
status = wlan.status()
if status < 0 or status >= 3:
break
max_wait -= 1
print('.')
time.sleep(1)
if wlan.isconnected():
print('Wi-Fi Connected!')
print('IP Address:', wlan.ifconfig()[0])
return True
else:
status = wlan.status()
error_dict = {
network.STAT_WRONG_PASSWORD: "Wrong password",
network.STAT_NO_AP_FOUND: "No AP found",
network.STAT_CONNECT_FAIL: "Connection failed"
}
print(f"Wi-Fi Connection Failed! Status code: {status} - {error_dict.get(status, 'Unknown error')}")
return False
except Exception as e:
print(f"Wi-Fi connection error: {e}")
return False
def send_telegram_message(token, chat_id, message):
url = f"https://api.telegram.org/bot{token}/sendMessage?chat_id={chat_id}&text={message}"
try:
print("Sending Telegram message...")
response = urequests.get(url, timeout=10)
if response.status_code == 200:
print(f"Message '{message}' sent successfully to chat ID {chat_id}!")
else:
print(f"Failed to send message. Status code: {response.status_code}")
print(f"Response: {response.text}")
response.close()
except Exception as e:
print(f"Error sending Telegram message: {e}")
def get_latest_telegram_message(token):
global last_update_id
url = f"https://api.telegram.org/bot{token}/getUpdates"
if last_update_id is not None:
url += f"?offset={last_update_id + 1}&limit=1&timeout=1"
else:
url += f"?limit=1&timeout=1"
try:
response = urequests.get(url, timeout=5)
if response.status_code == 200:
updates = response.json()
if "result" in updates and updates["result"]:
update = updates["result"][0]
last_update_id = update["update_id"]
message = update.get("message", {})
text = message.get("text", "").strip().lower()
chat_id = message.get("chat", {}).get("id", "")
return text, str(chat_id)
else:
print(f"Failed to fetch messages. Status code: {response.status_code}")
pass
response.close()
except Exception as e:
print(f"Error reading Telegram message: {e}")
return None, None
def handle_arm(chat_id_to_reply):
global armed_status
print("Executing ARM command.")
if armed_status:
send_telegram_message(TELEGRAM_BOT_TOKEN, chat_id_to_reply, "No need: System was already armed")
else:
armed_status = True
send_telegram_message(TELEGRAM_BOT_TOKEN, chat_id_to_reply, "System is now armed")
def handle_disarm(chat_id_to_reply):
global armed_status
print("Executing DISARM command.")
if not armed_status:
send_telegram_message(TELEGRAM_BOT_TOKEN, chat_id_to_reply, "No need: System was already disarmed")
else:
armed_status = False
send_telegram_message(TELEGRAM_BOT_TOKEN, chat_id_to_reply, "System is now disarmed")
# --- Main loop ---
wifi_connected = connect_wifi(WIFI_SSID, WIFI_PASSWORD)
if not wifi_connected:
print("Exiting: No Wi-Fi. Please check credentials or network.")
machine.reset()
else:
print("WiFi Init OK.")
send_telegram_message(TELEGRAM_BOT_TOKEN, TELEGRAM_MAIN_CHAT_ID, "WiFi Init OK.")
last_checked_time = time.time()
last_telegram_check_time = time.time()
while True:
triggered_pin_number = None
# Check all configured alarm pins
for i, pin_obj in enumerate(trigger_pins):
if pin_obj.value() == 0: # Pin is active low (triggered)
triggered_pin_number = IMMEDIATE_ALARM_PINS[i]
break # Exit loop once a trigger is found
if triggered_pin_number is not None:
if armed_status == False:
print(f"Sensor on PIN {triggered_pin_number} triggered, but system is not armed.")
else:
print(f"¡ALERT! Sensor on PIN {triggered_pin_number} triggered.")
send_telegram_message(TELEGRAM_BOT_TOKEN, TELEGRAM_MAIN_CHAT_ID, f"¡ALERT! Sensor on PIN {triggered_pin_number} triggered.")
current_pin_object = None
for i, pin_num_iter in enumerate(IMMEDIATE_ALARM_PINS):
if pin_num_iter == triggered_pin_number:
current_pin_object = trigger_pins[i]
break
if current_pin_object:
while current_pin_object.value() == 0:
time.sleep(0.1)
time.sleep(0.5) #
# Check Telegram messages periodically
current_time = time.time()
if current_time - last_telegram_check_time > 3:
if not wifi_connected:
print("Wi-Fi lost, attempting to reconnect...")
wifi_connected = connect_wifi(WIFI_SSID, WIFI_PASSWORD)
if wifi_connected:
print("Wi-Fi reconnected.")
send_telegram_message(TELEGRAM_BOT_TOKEN, TELEGRAM_MAIN_CHAT_ID, "Wi-Fi reconnected.")
else:
print("Failed to reconnect to Wi-Fi.")
last_telegram_check_time = current_time
time.sleep(10) # Wait before next loop iteration if wifi is down
continue
if wifi_connected:
msg, chat_id_from = get_latest_telegram_message(TELEGRAM_BOT_TOKEN)
if msg is not None and chat_id_from in ALLOWED_USERS:
print(f"Mensaje recibido de {chat_id_from}: {msg}")
if msg == "arm":
handle_arm(chat_id_from)
elif msg == "disarm":
handle_disarm(chat_id_from)
else:
send_telegram_message(TELEGRAM_BOT_TOKEN, chat_id_from, f"Unrecognized command: {msg}")
last_telegram_check_time = current_time
time.sleep(0.1)