Control your Nest thermostat with Twilio and FastAPI

Change the temperature on your Nest thermostat with a single text

import os
from fastapi import FastAPI, Request
from twilio.twiml.messaging_response import MessagingResponse
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import Flow, InstalledAppFlow
from googleapiclient.discovery import build

app = FastAPI()

# Set your Twilio Account SID, Auth Token, and Google Credentials JSON file
twilio_account_sid = "YOUR_TWILIO_ACCOUNT_SID"
twilio_auth_token = "YOUR_TWILIO_AUTH_TOKEN"
google_credentials_file = "YOUR_GOOGLE_CREDENTIALS_JSON_FILE"

# Set the device ID of your Nest thermostat
nest_thermostat_device_id = "YOUR_NEST_THERMOSTAT_DEVICE_ID"

# Set up Google API client
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = google_credentials_file
flow = InstalledAppFlow.from_client_secrets_file(google_credentials_file, ["https://www.googleapis.com/auth/sdm.service"])
credentials = flow.run_local_server(port=0)
google_api = build("smartdevicemanagement", "v1", credentials=credentials)

@app.post("/sms")
async def handle_sms(request: Request):
    form_data = await request.form()
    message_body = form_data.get("Body")
    try:
        temperature = int(message_body.strip())
    except ValueError:
        response = MessagingResponse()
        response.message("Invalid temperature value. Please send a valid number.")
        return str(response)

    try:
        set_temperature(nest_thermostat_device_id, temperature)
        response = MessagingResponse()
        response.message(f"Temperature set to {temperature}°F.")
        return str(response)
    except Exception as e:
        response = MessagingResponse()
        response.message("Failed to set temperature. Please try again.")
        return str(response)

def set_temperature(device_id: str, temperature_f: int):
    temperature_c = (temperature_f - 32) * (5 / 9)
    request_body = {
        "command" : "sdm.devices.commands.ThermostatTemperatureSetpoint.SetHeat",
        "params" : {"heatCelsius": temperature_c}
    }
    google_api.enterprises().devices().executeCommand(name=device_id, body=request_body).execute()

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)