I’m having trouble getting this seemingly simple function to work,
I want to send a SMS “reboot” to the sim800l, to simply reboot the device.
I have managed to get the device to reboot, but when it boots, the reboot command somehow comes back to the sms_message, and the device reboots, causing it to get stuck in a boot loop.
I have tried adding an on_boot function to clear the sms_message on boot, however this does not seem to help.
on_boot:
priority: 600
then:
- lambda: |-
// Clear the SMS message on boot
id(sms_message).publish_state("");
- lambda: |-
// Log the reboot event
ESP_LOGD("on_boot", "Device has rebooted. Waiting for GPS lock...");
What is causing the “reboot” command to keep coming back, the SMS is not being sent again and again?
Thanks
esphome:
name: "car-gps"
friendly_name: "car-gps"
on_boot:
priority: 600
then:
- lambda: |-
// Clear the SMS message on boot
id(sms_message).publish_state("");
- lambda: |-
// Log the reboot event
ESP_LOGD("on_boot", "Device has rebooted. Waiting for GPS lock...");
globals:
- id: sms_sent
type: bool
initial_value: "false"
- id: alarm_armed
type: bool
initial_value: "false"
- id: phone_number
type: std::string
restore_value: no
initial_value: '"redacted"' # Replace with your actual phone number
interval:
- interval: 10s
then:
- lambda: |-
if (!id(sms_sent) && id(gps_time).now().is_valid() && id(gps_satellites).state > 3) {
auto now = id(gps_time).now();
char buffer[100];
snprintf(buffer, sizeof(buffer), "Device rebooted successfully at (GPS time): %04d-%02d-%02d %02d:%02d:%02d UTC",
now.year, now.month, now.day_of_month, now.hour, now.minute, now.second);
id(gsm).send_sms(id(phone_number).c_str(), buffer);
id(sms_sent) = true;
ESP_LOGD("interval", "SMS sent successfully.");
} else if (!id(gps_time).now().is_valid() || id(gps_satellites).state <= 3) {
ESP_LOGD("interval", "Waiting for valid GPS time or sufficient satellites...");
}
esp32:
board: esp32dev
framework:
type: arduino
logger:
api:
encryption:
key: ""
reboot_timeout: 0s
ota:
platform: esphome
password: ""
wifi:
ap:
ssid: ""
password: ""
id: access_point
web_server:
port: 80
log: true
local: True
version: 3
include_internal: true
text_sensor:
- platform: template
id: sms_sender
name: "Sms Sender"
- platform: template
id: sms_message
name: "SMS Message"
update_interval: never
- platform: template
id: alarm_state
name: "Alarm State"
lambda: |-
if (id(alarm_armed)) {
return {"Armed"};
} else {
return {"Disarmed"};
}
update_interval: 10s
- platform: template
name: "Phone Number"
id: phone_number_sms
sensor:
- platform: uptime
name: Uptime
id: uptime_sensor
- platform: wifi_signal
name: "WiFi Signal Strength"
id: wifi_signal_sensor
update_interval: 30s
uart:
- id: sim
baud_rate: 9600
tx_pin: 27
rx_pin: 26
- id: gpsmodule
baud_rate: 9600
rx_pin: RX
sim800l:
id: gsm
uart_id: sim
on_sms_received:
# Publish the sender and message state to text sensors
- lambda: |-
id(sms_sender).publish_state(sender);
id(sms_message).publish_state(message);
# Check if the SMS sender is authorized
- lambda: |-
std::string sender_str = id(sms_sender).state.c_str();
if (sender_str != id(phone_number)) {
id(gsm).send_sms(sender_str.c_str(), "Unauthorized");
return;
}
# Handle the "phone_number" command to return the current phone number
- lambda: |-
auto sms_sender_raw = id(sms_sender).state;
auto sms_message_raw = id(sms_message).state;
std::string sms_sender(sms_sender_raw.begin(), sms_sender_raw.end());
std::string sms_message(sms_message_raw.begin(), sms_message_raw.end());
if (sms_sender == id(phone_number) && sms_message == "phone_number") {
std::string response = "The phone number is: " + id(phone_number);
id(gsm).send_sms(sms_sender.c_str(), response.c_str());
}
# Handle the "new_number" command to update the phone number
- lambda: |-
auto sms_sender_raw = id(sms_sender).state;
auto sms_message_raw = id(sms_message).state;
std::string sms_sender(sms_sender_raw.begin(), sms_sender_raw.end());
std::string sms_message(sms_message_raw.begin(), sms_message_raw.end());
if (sms_sender == id(phone_number) && sms_message.substr(0, 11) == "new_number ") {
std::string new_phone_number = sms_message.substr(11);
id(phone_number) = new_phone_number;
std::string response = "Phone number updated to: " + new_phone_number;
id(gsm).send_sms(sms_sender.c_str(), response.c_str());
}
# Handle "relay_on" and "relay_off" commands for the fuel shutoff relay
- lambda: |-
if ((id(sms_sender).state == id(phone_number)) &&
((id(sms_message).state == "relay_on") || (id(sms_message).state == "Relay_on"))) {
id(shutoff).turn_on(); // Turn the relay on
delay(100);
if (id(shutoff).state) {
id(gsm).send_sms(id(phone_number).c_str(), "Fuel Shutoff Relay has been turned on.");
} else {
id(gsm).send_sms(id(phone_number).c_str(), "Fuel Shutoff Relay failed to turn on.");
}
}
if ((id(sms_sender).state == id(phone_number)) &&
((id(sms_message).state == "relay_off") || (id(sms_message).state == "Relay_off"))) {
id(shutoff).turn_off(); // Turn the relay off
delay(100);
if (!id(shutoff).state) {
id(gsm).send_sms(id(phone_number).c_str(), "Fuel Shutoff Relay has been turned off.");
} else {
id(gsm).send_sms(id(phone_number).c_str(), "Fuel Shutoff Relay failed to turn off.");
}
}
# Handle the "where" command to send GPS and ignition data
- lambda: |-
auto to_lower = [](std::string str) -> std::string {
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
return str;
};
auto sms_sender_raw = id(sms_sender).state;
auto sms_message_raw = id(sms_message).state;
std::string sms_sender(sms_sender_raw.begin(), sms_sender_raw.end());
std::string sms_message_lower = to_lower(std::string(sms_message_raw.begin(), sms_message_raw.end()));
if (sms_sender == id(phone_number) && sms_message_lower == "where") {
std::string response;
if (id(latitude).has_state() && id(longitude).has_state()) {
float lat = id(latitude).state;
float lon = id(longitude).state;
response += "Device location:\n";
response += "Lat: " + std::to_string(lat) + "\n";
response += "Lon: " + std::to_string(lon) + "\n";
response += "Google Maps: https://www.google.com/maps?q=" + std::to_string(lat) + "," + std::to_string(lon) + "\n";
} else {
response += "GPS coordinates are not available yet.\n";
}
if (id(ignition).state) {
response += "Ignition: ON\n";
} else {
response += "Ignition: OFF\n";
}
if (id(speed).has_state()) {
float gps_speed = id(speed).state;
response += "Speed: " + std::to_string(gps_speed) + " km/h\n";
} else {
response += "Speed: N/A\n";
}
id(gsm).send_sms(id(phone_number).c_str(), response.c_str());
}
# Handle the "arm" and "disarm" commands to arm/disarm the alarm
- lambda: |-
auto sms_sender_raw = id(sms_sender).state;
auto sms_message_raw = id(sms_message).state;
std::string sms_sender(sms_sender_raw.begin(), sms_sender_raw.end());
std::string sms_message(sms_message_raw.begin(), sms_message_raw.end());
auto to_upper = [](std::string str) -> std::string {
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
return str;
};
sms_message = to_upper(sms_message);
if (sms_sender == id(phone_number)) {
if (sms_message == "ARM") {
id(alarm_armed) = true;
id(shutoff).turn_on();
id(gsm).send_sms(id(phone_number).c_str(), "Alarm armed. Notifications enabled, and fuel shutoff is ON.");
ESP_LOGD("sms", "Alarm armed by SMS.");
} else if (sms_message == "DISARM") {
id(alarm_armed) = false;
id(shutoff).turn_off();
id(gsm).send_sms(id(phone_number).c_str(), "Alarm disarmed. Notifications disabled, and fuel shutoff is OFF.");
ESP_LOGD("sms", "Alarm disarmed by SMS.");
}
}
- lambda: |-
if (id(sms_sender).state == id(phone_number) && id(sms_message).state == "reboot") {
id(gsm).send_sms(id(phone_number).c_str(), "Rebooting device...");
// Clear the SMS message immediately to avoid loop
id(sms_message).publish_state("");
// Trigger the reboot
id(reboot_trigger).turn_on();
}
# Handle the "STATUS" command to return sensor data
- lambda: |-
id(sms_sender).publish_state(sender);
id(sms_message).publish_state(message);
auto sms_sender_raw = id(sms_sender).state;
auto sms_message_raw = id(sms_message).state;
std::string sms_sender(sms_sender_raw.begin(), sms_sender_raw.end());
std::string sms_message(sms_message_raw.begin(), sms_message_raw.end());
auto to_upper = [](std::string str) -> std::string {
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
return str;
};
sms_message = to_upper(sms_message);
if (sms_sender == id(phone_number) && sms_message == "STATUS") {
std::string response;
if (id(gps_time).now().is_valid()) {
response += "GPS Fix: True\n";
} else {
response += "GPS Fix: False\n";
}
if (id(gps_satellites).has_state()) {
response += "Satellites: " + std::to_string((int)id(gps_satellites).state) + "\n";
} else {
response += "Satellites: N/A\n";
}
if (id(uptime_sensor).has_state()) {
int total_seconds = (int)id(uptime_sensor).state;
int days = total_seconds / 86400;
int hours = (total_seconds % 86400) / 3600;
int minutes = (total_seconds % 3600) / 60;
response += "Uptime: " + std::to_string(days) + "d " + std::to_string(hours) + "h " + std::to_string(minutes) + "m\n";
} else {
response += "Uptime: N/A\n";
}
if (id(ignition).state) {
response += "Ignition: ON\n";
} else {
response += "Ignition: OFF\n";
}
if (id(shutoff).state) {
response += "Relay: ON\n";
} else {
response += "Relay: OFF\n";
}
if (id(alarm_armed)) {
response += "Alarm State: Armed\n";
} else {
response += "Alarm State: Disarmed\n";
}
id(gsm).send_sms(id(phone_number).c_str(), response.c_str());
}
# Fallback for unrecognized commands
- lambda: |-
auto sms_sender_raw = id(sms_sender).state;
auto sms_message_raw = id(sms_message).state;
std::string sms_sender(sms_sender_raw.begin(), sms_sender_raw.end());
std::string sms_message(sms_message_raw.begin(), sms_message_raw.end());
std::vector<std::string> valid_commands = {"ARM", "DISARM", "STATUS", "REBOOT", "WHERE", "RELAY_ON", "RELAY_OFF", "PHONE_NUMBER"};
auto to_upper = [](std::string str) -> std::string {
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
return str;
};
sms_message = to_upper(sms_message);
if (sms_sender == id(phone_number)) {
bool is_valid_command = false;
for (auto& command : valid_commands) {
if (sms_message == command) {
is_valid_command = true;
break;
}
}
if (!is_valid_command) {
if (sms_message == "PHONE_NUMBER") {
std::string response = "The current phone number is: " + id(phone_number);
id(gsm).send_sms(sms_sender.c_str(), response.c_str()); // Send SMS back to sender
} else {
id(gsm).send_sms(id(phone_number).c_str(), "Unrecognized Command");
}
}
}
binary_sensor:
- platform: gpio
id: ignition
pin:
number: 21
mode: INPUT_PULLUP
inverted: True
name: "Ignition"
filters:
- delayed_on: 1000ms
- delayed_off: 1000ms
on_press:
then:
- lambda: |-
if (id(alarm_armed)) {
id(gsm).send_sms(id(phone_number).c_str(), "ALERT: Ignition turned ON while alarm is armed!");
ESP_LOGD("ignition", "Ignition notification sent: Alarm is armed.");
} else {
ESP_LOGD("ignition", "Ignition ON detected, but alarm is not armed. No notification sent.");
}
switch:
- platform: gpio
name: "SIM800_PWKEY"
pin: 4
restore_mode: ALWAYS_OFF
- platform: gpio
name: "SIM800_RST"
pin: 5
restore_mode: ALWAYS_ON
- platform: gpio
name: "SIM800_POWER"
pin: 23
restore_mode: ALWAYS_ON
- platform: gpio
id: shutoff
pin: 14
name: "Fuel Shutoff"
inverted: True
button:
- platform: restart
id: reboot_trigger
on_press:
- lambda: |-
ESP.restart();
# Declare GPS module
gps:
uart_id: gpsmodule
id: gps_sensor
update_interval: 60s
latitude:
name: "GPS Latitude"
id: latitude
longitude:
name: "GPS Longitude"
id: longitude
speed:
name: "GPS Speed"
id: speed
satellites:
name: "GPS Satellites"
id: gps_satellites
time:
- platform: gps
id: gps_time