I'm writing a program to toggle the lights at my house based on my iPhone's GPS coordinates. Below is what I have so far. However, I feel like there must be a better way to do this. Is there a way to get GPS data without pinging my phone every five minutes?
So far I've tried the following with no joy:
Using Shortcuts and Scriptable I tried to write some JavaScript that would trigger when I got close to home. However, I could not figure out how to use await require('wemo-client') using scriptablify. I kept getting an error, "ReferenceError: Can't find variable: require".
IFTTT does not have a variable timed trigger so the lights won't turn off after 15 minutes. Also, I plan on adding a motion sensor trigger that is unsupported.
Pythonista is $10. Yes, I am that cheap.
Apple HomeKit does not support the model I'm using, Wemo Smart Light Switch F7C030.
The code below works, but I hate that I have to ping my phone every five minutes. I'd rather save battery life by firing this code once or twice a day, as needed.
Any suggestions would be greatly appreciated.
Code:
import sys
import time
import datetime
import os
from pyicloud import PyiCloudService
import pywemo
APPLE_ID = os.getenv('APPLE_ID') # Apple ID username
APPLE_ID_PASSWORD = os.getenv('APPLE_ID_PASSWORD') # Apple ID password
API = PyiCloudService(APPLE_ID, APPLE_ID_PASSWORD)
IPHONE = API.devices[1]
LOCATION = IPHONE.location()
FIVE = 300 # 5 * 60 seconds
FIFTEEN = 900 # 15 * 60 seconds
ONEMILE = 0.01449275362318840579710144927536 # one mile is 1/69 degrees lat or long
HOMELAT = # my home's latitude
HOMELONG = # my home's longitude
WEMOS = pywemo.discover_devices()
LEN_WEMOS = range(len(WEMOS))
# Two factor authentication to retrieve iPhone data
if API.requires_2fa:
import click
print("Two-step authentication required. Your trusted devices are:")
DEVICES = API.devices
for i, device in enumerate(DEVICES):
print(" %s: %s" % (i, device.get('deviceName', "SMS to %s" % device.get('phoneNumber'))))
DEF_DEVICE = click.prompt('Which device would you like to use?', default=0)
DEVICE = DEVICES[DEF_DEVICE]
if not API.send_verification_code(DEVICE):
print("Failed to send verification code")
sys.exit(1)
CODE = click.prompt('Please enter validation code')
if not API.validate_verification_code(DEVICE, CODE):
print("Failed to verify verification code")
sys.exit(1)
# Turn off the lights when I leave
def leavehome():
timenow = datetime.datetime.now()
print("Left home on {}".format(timenow.strftime("%B %d, %Y at %H:%M:%S")))
for wemo in LEN_WEMOS:
WEMOS[wemo].off()
# Turn on the lights for 15 minutes when I get home
def arrivehome():
timenow = datetime.datetime.now()
print("Arrived home on {}".format(timenow.strftime("%B %d, %Y at %H:%M:%S")))
# Loop through all Wemo devices
for wemo in LEN_WEMOS:
WEMOS[wemo].on()
time.sleep(FIFTEEN)
for wemo in LEN_WEMOS:
WEMOS[wemo].off()
# Automatically turn off the lights after 15 minutes - save electricity
def timeoff():
time.sleep(FIFTEEN)
for wemo in LEN_WEMOS:
WEMOS[wemo].off()
# Ping my phone for GPS data
def pingphone(prev):
mylat = LOCATION["latitude"]
mylong = LOCATION["longitude"]
logic(prev, mylat, mylong)
time.sleep(FIVE)
# Perform logic to determine if I'm home, out, arriving, or leaving
def logic(prev, lat, long):
inrange = (HOMELAT+ONEMILE >= lat >= HOMELAT-ONEMILE and HOMELONG+ONEMILE >= long >= HOMELONG-ONEMILE)
current = bool(inrange)
previous = prev
if current and not previous:
arrivehome()
elif previous and not current:
leavehome()
else:
timeoff()
pingphone(current)
# Run the script
pingphone(False)
Related
I'm trying to adjust the volume of an instance of vlc.MediaPlayer before playback. Running the below snippet (python3 test.py) plays five seconds of the audio file path/to/file.m4a. It appears that audio_set_volume does actually set the volume of the player, given that the subsequent print statement returns 10; but there's no practical change in volume (whether I set it lower or higher).
# test.py
import vlc
from time import sleep
media_player = vlc.MediaPlayer("path/to/file.m4a")
# Set the volume to 10%
media_player.audio_set_volume(10)
# Returns 10
print("Set volume: " + str(media_player.audio_get_volume()))
media_player.play()
sleep(5)
This similar question doesn't appear to have been resolved.
Versions:
Python==3.10.6
python-vlc==3.0.16120
You didn't create a vlc.Instance() which probably won't help matters.
Try:
import vlc
from time import sleep
instance = vlc.Instance()
media_player = instance.media_player_new()
media = instance.media_new('./vp1.mp3')
media_player.set_media(media)
media.parse()
media_player.audio_set_volume(30)
media_player.play()
print("Starting Volume "+ str(media_player.audio_get_volume()))
low = True
while True:
sleep(5)
if low:
media_player.audio_set_volume(150)
low = False
print("vol 150")
else:
media_player.audio_set_volume(50)
low = True
print("vol 50")
See if you get any mileage from that?
Hello everybody, hope you are all doing well.
I am doing in a project in which I receive GPS data (Longitude, and Latitude) from an Android device via an SQL server. What I am trying to do is to send this Longitude - Latitude data to my SITL vehicle in Ardupilot. I thought about using Dronekit Python API as such:
from dronekit import connect, VehicleMode
import time
import mysql.connector
import time
#--- Start the Software In The Loop (SITL)
import dronekit_sitl
#
sitl = dronekit_sitl.start_default() #(sitl.start)
#connection_string = sitl.connection_string()
mydb = mysql.connector.connect(
host="******",
user="******",
password="*****",
database="koordinat"
)
mycursor = mydb.cursor()
#--- Now that we have started the SITL and we have the connection string (basically the ip and udp port)...
print("Araca bağlanılıyor")
vehicle = connect('tcp:127.0.0.1:5762', wait_ready=False, baud = 115200)
vehicle.wait_ready(True, raise_exception=False)
#-- Read information from the autopilot:
#- Version and attributes
vehicle.wait_ready('autopilot_version')
print('Autopilot version: %s'%vehicle.version)
#- Does the firmware support the companion pc to set the attitude?
print('Supports set attitude from companion: %s'%vehicle.capabilities.set_attitude_target_local_ned)
vehicle.mode = VehicleMode("GUIDED")
vehicle.armed = True
while(True):
mycursor.execute("SELECT * FROM koordinat WHERE 1")
location = str(mycursor.fetchall())
location = location.split(",")
location[0] = location[0].replace("[", "")
location[0] = location[0].replace("(", "")
location[0] = location[0].replace("'", "")
location[1] = location[1].replace("[", "")
location[1] = location[1].replace(")", "")
location[1] = location[1].replace("'", "")
location[1] = location[1].replace(")", "")
# Converting the longitude and latitude to float, before assigning to the vehicle GPS data:
location[0] = float(location[0])
location[1] = float(location[1])
# Setting the location of the vehicle:
vehicle.location.global_frame.lat = location[0]
vehicle.location.global_frame.lon = location[1]
print('Konum:', str(vehicle.location.global_frame.lat)+str(","), str(vehicle.location.global_frame.lon)+str(","), str(vehicle.location.global_frame.alt))
#- When did we receive the last heartbeat
print('Son bilgi gelişi: %s'%vehicle.last_heartbeat)
time.sleep(1)
However, when I check from the SITL and Mission Planner (also from the print statement from my code) the location does not change; the simulator simply ignores those commands sent by the Dronekit. Is there a working method to accomplish what I am trying to do? I tried to change the sim_vehicle.py script which I use to start the simulation. But I was only able to change the starting/home location of the vehicle. I was not able to change the current location of the vehicle on SITL and Mission Planner.
This is incorrect. You're modifying the attribute of the vehicle object that's connected to the SITL, not sending any commands to the actual autopilot.
vehicle.location.global_frame.lat = location[0]
vehicle.location.global_frame.lon = location[1]
What you want to do is set the mode to GUIDED and use the simple_goto function in dronekit to make the drone move to lat/lon/alt coordinates.
Otherwise, you can also send this MAVLink command SET_POSITION_TARGET_GLOBAL_INT to guide it.
I'm trying to establish a weather station with a Raspberry Pi 3
the code will be written in Python
the Raspberry Pi will be connected directly with an Adafruit DHT-22 Sensor
a BMP-180 Sensor and a DS18B20 Sensor
the remote station will use an ESP-8266
and also the Raspberry Pi will be taking measurements from the Open Weather Maps
there's going to be a GUI and also the measurements will be displayed on Thinkspeak (for the IOT part)
My problem now
I want to display all the measurements from the sensors but also I want to display the difference from the ESP-8266 Sensor and the Open Weather Maps
#something like this#
"the difference in temperature from the station and the satellite is ..."
#or#
"the measurements are equal"
is there a way to create a command in Python that does just that
because Pycharm wasn't happy with my code ...
import Adafruit_DHT
import pyowm
DHT22Sensor = Adafruit_DHT.DHT22
DHTpin = 16
humidity_indoors, temperature_indoors = Adafruit_DHT.read_retry(DHT22Sensor, DHTpin)
degree_sign = u'\N{DEGREE SIGN}'
owm = pyowm.OWM('')
observation = owm.weather_at_place('Larissa, GR')
weather_sat = observation.get_weather()
status_sat = weather.get_detailed_status()
temperature_sat = weather.get_temperature('celsius')['temp']
wind_sat = weather.get_wind('miles_hour')['speed']
humidity_sat = weather.get_humidity()
def mphtokmh(wind):
kmh = (float)(wind * 1.60)
return kmh
if humidity_indoors is not None and temperature_indoors is not None :
print('Temp={0:0.1 f} * C Humidity={1:0.1 f}%' .format(temperature_indoors, humitity_indoors))
else :
print('Failed to get reading, Try Again!')
print("The Sky is...{}".format(status_sat))
print("the temperature in our town is...{}C".format(temperature_sat))
print("the windspeed is...{}Km/h".format(wind_sat))
print("humid is...{}"%.format(humitity_sat))
if temperature_sat==temperature_indoors
print("No Difference to show")
if temperature_sat>temperature_indoors
print(temperature_sat)
if temperature_sat<temperature_indoors
print(temperature_indoors)
(ps this is just a test code)
I have a dust sensor, and I have to measure a sum of inactive time in 30 seconds cycles.
For DigitalInputDevice gpiozero provides cool functionality, I mean two properties, and two callbacks:
properties - active_time (return float if pin is active or None) and inactive_time
(return float if pin is inactive or None),
callbacks - when_activated and when_deactivated
I thought that inside those callbacks I would have access to the digit input in the previous state, which would allow me to grab active time when pin change state to inactive, and inactive time when pin change state to active, but I was wrong.
So my question is: There is any possibility in this library to grab a whole active time when pin turns to inactive and vice versa?
Thank you!
Clarification: what I want is described in the image below
image of chart my sensor docs: https://botland.com.pl/index.php?controller=attachment&id_attachment=1565
I do it now in this way:
from gpiozero import DigitalInputDevice
from datetime import timedelta
import time
sensor_one_micrometer = DigitalInputDevice(20)
while True:
active_time = 0
inactive_time = 0
sensor_one_micrometer.wait_for_active()
while active_time + inactive_time < 30:
watch_start = time.time()
sensor_one_micrometer.wait_for_inactive()
active_time += time.time() - watch_start
watch_start = time.time()
sensor_one_micrometer.wait_for_active()
inactive_time += time.time() - watch_start
percent = inactive_time/(active_time+inactive_time)
print("Active Time: ", active_time)
print("Inactive Time: ", inactive_time)
print(
inactive_time/(active_time+inactive_time)
)
I'm doing a telemetry application using Azure IoT Hub, Azure IoT SDK in Python and a raspberry pi with temperature and humidity sensors.
Humidity + Temperature sensors => Rasperry Pi => Azure IoT Hub
In my first implementation thanks azure examples, I used one loop that collect data from the temperature sensor and the humidity sensor, and send them to Azure IoT Hub in the same time every 60 second.
>>> 1 Loop every 60s = Collect data & send data of temperature and humidity
Now I would like to send them with different frequencies, I mean :
One loop will collect the data of the temperature sensor and send it to Azure IoT Hub every 60 seconds;
Whereas a second loop will collect the data of the humidity sensor and send it to Azure IoT Hub every 600 seconds.
>>> 1 Loop every 60s= Collect data & send data of temperature
>>> 2 Loop every 600s= Collect data & send data of humidity
I think the tool I need is multi-threading, but I don't understand which library or structure I have to implement in my case.
Here is the code provided by Azure, including one loop that handles temperature and humidity at the same time. Reading the data and sending to Azure every 60 seconds.
import random
import time
import sys
# Using the Python Device SDK for IoT Hub:
from iothub_client import IoTHubClient, IoTHubClientError,
IoTHubTransportProvider, IoTHubClientResult
from iothub_client import IoTHubMessage, IoTHubMessageDispositionResult,
IoTHubError, DeviceMethodReturnValue
# The device connection string to authenticate the device with your IoT hub.
CONNECTION_STRING = "{Your IoT hub device connection string}"
# Using the MQTT protocol.
PROTOCOL = IoTHubTransportProvider.MQTT
MESSAGE_TIMEOUT = 10000
# Define the JSON message to send to IoT Hub.
TEMPERATURE = 20.0
HUMIDITY = 60
MSG_TXT = "{\"temperature\": %.2f,\"humidity\": %.2f}"
def send_confirmation_callback(message, result, user_context):
print ( "IoT Hub responded to message with status: %s" % (result) )
def iothub_client_init():
# Create an IoT Hub client
client = IoTHubClient(CONNECTION_STRING, PROTOCOL)
return client
def iothub_client_telemetry_sample_run():
try:
client = iothub_client_init()
print ( "IoT Hub device sending periodic messages, press Ctrl-C to exit" )
#******************LOOP*******************************
while True:
# Build the message with simulated telemetry values.
temperature = TEMPERATURE + (random.random() * 15)
humidity = HUMIDITY + (random.random() * 20)
msg_txt_formatted = MSG_TXT % (temperature, humidity)
message = IoTHubMessage(msg_txt_formatted)
# Send the message.
print( "Sending message: %s" % message.get_string() )
client.send_event_async(message, send_confirmation_callback, None)
time.sleep(60)
except IoTHubError as iothub_error:
print ( "Unexpected error %s from IoTHub" % iothub_error )
return
except KeyboardInterrupt:
print ( "IoTHubClient sample stopped" )
if __name__ == '__main__':
print ( "IoT Hub Quickstart #1 - Simulated device" )
print ( "Press Ctrl-C to exit" )
iothub_client_telemetry_sample_run()
I would like to use the same structure of functions, including two loops that handles temperature and humidity, one every 60s and one every 600s.
while True:
# Build the message with simulated telemetry values.
temperature = TEMPERATURE + (random.random() * 15)
msg_txt_formatted1 = MSG_TXT1 % (temperature)
message1 = IoTHubMessage(msg_txt_formatted1)
# Send the message.
print( "Sending message: %s" % message1.get_string() )
client.send_event_async(message1, send_confirmation_callback, None)
time.sleep(60)
while True:
# Build the message with simulated telemetry values.
humidity = HUMIDITY + (random.random() * 20)
msg_txt_formatted2 = MSG_TXT2 % (humidity)
message2 = IoTHubMessage(msg_txt_formatted2)
# Send the message.
print( "Sending message: %s" % message2.get_string() )
client.send_event_async(message2, send_confirmation_callback, None)
time.sleep(600)
How can I do that? How to call those loops with multi-threading or another method?
It may be simpler to do something like
while True:
loop_b()
for _ in range(10):
loop_a()
time.sleep(60)
or even
while True:
time.sleep(1)
now = time.time()
if now % 60 == 0:
loop_a()
if now % 600 == 0:
loop_b()
But if you really want to use threads, then:
import threading
class LoopAThread(threading.Thread):
def run(self):
loop_a()
class LoopBThread(threading.Thread):
def run(self):
loop_b()
...
thread_a = LoopAThread()
thread_b = LoopBThread()
thread_a.start()
thread_b.start()
thread_a.join()
thread_b.join()
Here are two competing approaches to consider
Don't bother with threads at all. Just have one loop that sleeps every 60 seconds like you have now. Keep track of the last time you sent humidity data. If 600 seconds has passed, then send it. Otherwise, skip it and go to sleep for 60 seconds. Something like this:
from datetime import datetime, timedelta
def iothub_client_telemetry_sample_run():
last_humidity_run = None
humidity_period = timedelta(seconds=600)
client = iothub_client_init()
while True:
now = datetime.now()
send_temperature_data(client)
if not last_humidity_run or now - last_humidity_run >= humidity_period:
send_humidity_data(client)
last_humidity_run = now
time.sleep(60)
Rename iothub_client_telemetry_sample_run to temperature_thread_func or something like it. Create a separate function that looks just like it for humidity. Spawn two threads from the main function of your program. Set them to daemon mode so they shutdown when the user exits
from threading import Thread
def temperature_thread_func():
client = iothub_client_init()
while True:
send_temperature_data(client)
time.sleep(60)
def humidity_thread_func():
client = iothub_client_init()
while True:
send_humidity_data(client)
time.sleep(600)
if __name__ == '__main__':
temp_thread = Thread(target=temperature_thread_func)
temp_thread.daemon = True
humidity_thread = Thread(target=humidity_thread_func)
humidity_thread.daemon = True
input('Polling for data. Press a key to exit')
Notes:
If you decide to use threads, consider using an
event
to terminate them cleanly.
time.sleep is not a precise way to keep
time. You might need a different timing mechanism if the samples need
to be taken at precise moments.