Vivint Smart Garage Auto Close

Vivint Smart Garage Auto Close
Photo by Vivint Solar / Unsplash

My car recently got stolen out of my garage so I wrote a script to automatically close the garage whenever both of our phones are not connected to the home Wifi.

Thanks to Nate K Spencer and this repository for the Vivint API integration needed to make this possible: https://github.com/natekspencer/vivintpy

To check that our phones are on our home WiFi, I used DHCP reservations so that they always have the same IP addresses. I had already done this for other purposes, so this was an easy step.

This all being said, I don't recommend Vivint Smart Home as they do not integrate well with other smart home vendors.

The script:

import asyncio
import logging
import os

import pubnub
import subprocess

from vivintpy.account import Account
from vivintpy.devices import VivintDevice
from vivintpy.devices.garage_door import GarageDoor
from vivintpy.exceptions import VivintSkyApiMfaRequiredError

pubnub.set_stream_logger(name="pubnub", level=logging.ERROR)


# Check if phone is on WiFi
def on_wifi():
    logging.debug("Checking for devices...")
    briana_phone = False
    trevor_phone = False

    try:
        briana_phone = subprocess.check_output(["ping", "-c", "1", "-t", "1", "192.168.1.7"])
    except subprocess.CalledProcessError:
        pass

    try:
        trevor_phone = subprocess.check_output(["ping", "-c", "1", "-t", "1", "192.168.1.6"])
    except subprocess.CalledProcessError:
        pass

    if not briana_phone and not trevor_phone:
        logging.debug("Devices not present!")
        return False
    else:
        logging.debug("Devices present...")
        return True


async def main():
    logging.getLogger().setLevel(logging.DEBUG)
    logging.debug("Demo started")

    def camera_motion_callback(device: VivintDevice) -> None:
        logging.debug("Motion detected from camera: %s", device)

    account = Account(username='[email protected]', password='mypassword')
    try:
        await account.connect(load_devices=True, subscribe_for_realtime_updates=True)
    except VivintSkyApiMfaRequiredError:
        code = input("Enter MFA Code: ")
        await account.verify_mfa(code)
        logging.debug("MFA verified")

    try:
        while True:
            if not on_wifi():
                logging.debug("Discovered systems & devices:")
                for system in account.systems:
                    logging.debug(f"\tSystem {system.id}")
                    for alarm_panel in system.alarm_panels:
                        logging.debug(
                            f"\t\tAlarm panel {alarm_panel.id}:{alarm_panel.partition_id}"
                        )
                        for device in alarm_panel.devices:
                            logging.debug(f"\t\t\tDevice: {device}")
                            if isinstance(device, GarageDoor):
                                logging.debug("Closing garage door")
                                await device.close()
            
            await asyncio.sleep(10)
            await account.refresh()
    except Exception as e:
        logging.debug(e)
    finally:
        await account.disconnect()


if __name__ == "__main__":
    asyncio.run(main())