This a somewhat general question so forgive me if I'm breaking any guidelines.
I'm writing a JQuery / websocket / Flask application that uses a Raspberry Pi to monitor some sensors as well as manage some active hardware. Multiple classes and objects spawned by my Flask-implemented server need to be able to access my hardware.
Based off my programming background (relatively new to Python) I would gravitate to a static class with class methods that operate without instantiation.
I've found documentation on how to do that in Python but I'm not sure it's the best approach. Is it more Pythonic to instantiate an object and pass it around or ... ?
Here is the non-static object oriented code I'm using now (I'm thinking a static version of the following will suite my needs but I want to do what is most appropriate for the language):
import os
import glob
import time
import RPi.GPIO as GPIO
#class to manage hardware -- sensors, pumps, etc
class Hardware:
#system params for sensor
os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')
#global vars for sensor
base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28*')[0]
device_file = device_folder + '/w1_slave'
#global var for program
temp_unit = 'F' #temperature unit, choose C for Celcius or F for F for Farenheit
temp_target = 69 #target temperature to cool to in chosen unit
temp_log_loc = '/var/www/hw-log.csv' #location of temp log, by default Raspberry Pi Apache server
gpio_pin = 17
#function to enable GPIO
def gpio_active(self,active):
if active is True:
GPIO.setmode(GPIO.BCM)
GPIO.setup(self.gpio_pin, GPIO.OUT)
else:
GPIO.cleanup()
#def __init__(self): Not used
#reads raw temp from sensor
def read_temp_raw(self):
f = open(self.device_file, 'r')
lines = f.readlines()
f.close()
return lines
#cleans up raw sensor data, returns temp in unit of choice
def read_temp(self):
lines = self.read_temp_raw()
while lines[0].strip()[-3:] != 'YES':
time.sleep(0.2)
lines = self.read_temp_raw()
equals_pos = lines[1].find('t=')
if equals_pos != -1:
temp_string = lines[1][equals_pos+2:]
temp_c = float(temp_string) / 1000.0
temp_f = temp_c * 9.0 / 5.0 + 32.0
if self.temp_unit == 'F':
return temp_f
else:
return temp_c
#**********sensors**********
#mashtun sensor
##staticmethod
def mashtun_temp(self):
return self.read_temp()
#hot liquor tank sensor
def htl_temp(self):
return 200
#fermentor sensor
def fermentor_temp(self):
return 65
#**********pumps**********
def herms_pump_active(self,active):
self.gpio_active(True)
if active is True:
print('***Hardware report: Setting HERMS pump on***')
GPIO.output(self.gpio_pin,GPIO.LOW)
else:
print('Setting HERMS pump off')
GPIO.output(self.gpio_pin,GPIO.HIGH)
self.gpio_active(False)
Related
So I added this line to my crontab at the end of the file, but I cannot seem to get my program to run. I'm not logging anything in my scubot.log so that's not very helpful. Not sure what I'm doing wrong, I've tried several solutions to this but can't seem to find any good information, at least nothing that fits my case.
#reboot sleep 15; /usr/bin/python3 /home/pi/Documents/scubot/scubot.py >> /home/pi/Documents/scubot/scubot.log
from sqlite3 import Date, Error
import ssl
import requests
import configparser
from datetime import date, datetime
import schedule
import time
import emailHelper
from email_templates import emails
# import RPi.GPIO as GPIO
# import time
config = configparser.ConfigParser()
config.read(".config")
configstuff = config['Weather_API']['weatherAPIKey']
lat = "41.6884"
long = "-93.7925"
import pymongo
# Replace the uri string with your MongoDB deployment's connection string.
conn_str = "mongodb+srv://sensitive.nqx9x.mongodb.net/?retryWrites=true&w=majority"
# set a 5-second connection timeout
client = pymongo.MongoClient(conn_str, serverSelectionTimeoutMS=5000)
db = client.scubot
weatherDataCollection = db.weatherdata
# create env to only run this when on the raspberry pi?
import os
import time
os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')
device_file = '/sys/devices/w1_bus_master1/28-0620111704e4/w1_slave'
print('Scubot Started')
def read_temp_raw():
f = open(device_file, 'r')
lines = f.readlines()
f.close()
print('lines', lines)
return lines
def read_temp():
lines = read_temp_raw()
while lines[0].strip()[-3:] != 'YES':
time.sleep(0.2)
lines = read_temp_raw()
equals_pos = lines[1].find('t=')
if equals_pos != -1:
temp_string = lines[1][equals_pos+2:]
print('temp string', temp_string)
temp_c = float(temp_string) / 1000.0
temp_f = temp_c * 9.0 / 5.0 + 32.0
return temp_f
response = requests.get("https://api.openweathermap.org/data/2.5/weather?lat=" + lat + "&lon=" + long + "&units=imperial&appid=" + configstuff + "").json()
weather = response['main']
city = response['name']
icon = response['weather'][0]['icon']
number1 = 498474239847239
boolean = True
# print(city)
# print(weather)
def storeWeatherData():
try:
weatherData = {
"city": city,
"outsideTemp" : weather['temp'],
"humidity" : weather['humidity'],
"outsidePressure" : weather['pressure'],
"lat": lat,
"long": long,
"shallowProbeTemp": "{:.2f}".format(read_temp()),
"dateOfTempReading": datetime.now()
}
weatherDataCollection.insert_one(weatherData)
print(weatherData, 'Successfully inserted into the database')
except Exception:
print(Exception)
# emailHelper.sendEmail(['test'], 'testing scuba app', emails.temperatureEmail(weather['temp'], lat, long))
# # This uses a scheduler to run a certain function every day. We can set this to minutes or hours or days.
schedule.every(1).minutes.do(storeWeatherData)
while True:
schedule.run_pending()
time.sleep(1)
I have this script that runs continuously on a raspbery Zero to capture the temperatures and send them to grafana the problem is that when the grafana server is stopped for backup or something, the script falls in error and does not automatically resume so I’m looking for a way to create a connection test loop prealable to sending data and if the grafana server is off-service the continuous script worked until the grafana server was up and running and therefore resumed sending the temperature data to the grafana server.
Because current I end up with the script in error with in the message
requests.exceptions.ConnectionError: HTTPConnectionPool
To use script
python templogger.py -db=influx_db_temperature -sn=temperature -rn=RUN
My script :
#!/usr/bin/python
# -*- coding: utf-8 -*-
import os
import glob
import argparse
import time
import datetime
import sys
from influxdb import InfluxDBClient
os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')
# add more sensor variables here based on your setup
# For multiple sensor
# temp=['sensor code','tttttttttt','ddddddddddd','ssssssssss']
temp=['0120215dbea2','0120327e05bf']
base_dir = '/sys/bus/w1/devices/'
# Ext = 28-0120215dbea2
# Int = 28-0120327e05bf
device_folders = glob.glob(base_dir + '28*')
snum=2 #Number of connected temperature sensors
# Set required InfluxDB parameters.
# (this could be added to the program args instead of beeing hard coded...)
host = "NasGrafana.lan.prive" #Could also use local ip address like "192.168.1.136"
port = 8086
user = "temperature"
password = "12345678"
# Sample period (s).
# How frequently we will write sensor data from the temperature sensors to the database.
sampling_period = 120
def read_temp_raw(device_file):
f = open(device_file, 'r')
lines = f.readlines()
f.close()
return lines
def read_temp(device_file): # checks the temp recieved for errors
lines = read_temp_raw(device_file)
while lines[0].strip()[-3:] != 'YES':
time.sleep(0.2)
lines = read_temp_raw(device_file)
equals_pos = lines[1].find('t=')
if equals_pos != -1:
temp_string = lines[1][equals_pos+2:]
# set proper decimal place for C
temp = float(temp_string) / 1000.0
# Round temp to 2 decimal points
temp = round(temp, 1)
# value of temp might be unknown here if equals_pos == -1
return temp
def get_args():
'''This function parses and returns arguments passed in'''
# Assign description to the help doc
parser = argparse.ArgumentParser(description='Program writes measurements data from the connected DS18B20 to specified influx db.')
# Add arguments
parser.add_argument(
'-db','--database', type=str, help='Database name', required=True)
parser.add_argument(
'-sn','--session', type=str, help='Session', required=True)
now = datetime.datetime.now()
parser.add_argument(
'-rn','--run', type=str, help='Run number', required=False,default=now.strftime("%Y%m%d%H%M"))
# Array of all arguments passed to script
args=parser.parse_args()
# Assign args to variables
dbname=args.database
runNo=args.run
session=args.session
return dbname, session,runNo
def get_data_points():
# Get the three measurement values from the DS18B20 sensors
for sensors in range (snum): # change number of sensors based on your setup
device_file=device_folders[sensors]+ '/w1_slave'
temp[sensors] = read_temp(device_file)
print (device_file,sensors,temp[sensors])
# Get a local timestamp
timestamp=datetime.datetime.utcnow().isoformat()
NumDevice=os.path.basename(os.path.dirname(device_file))
# Create Influxdb datapoints (using lineprotocol as of Influxdb >1.1)
datapoints = [
{
"measurement": session,
# "tags": {"runNum": NumDevice,},
"tags": {"runNum": runNo,},
"time": timestamp,
#"fields": {"temperature 1":temp[0],"temperature 2":temp[1],"temperature 3":temp[2],"temperature 4":temp[3]}
"fields": {"temperature 1":temp[0],"temperature 2":temp[1]}
}
]
return datapoints
# Match return values from get_arguments()
# and assign to their respective variables
dbname, session, runNo =get_args()
print ("Session: ", session)
print ("Run No: ", runNo)
print ("DB name: ", dbname)
# Initialize the Influxdb client
client = InfluxDBClient(host, port, user, password, dbname)
try:
while True:
# Write datapoints to InfluxDB
datapoints=get_data_points()
bResult=client.write_points(datapoints)
print("Write points {0} Bresult:{1}".format(datapoints,bResult))
# Wait for next sample
time.sleep(sampling_period)
# Run until keyboard ctrl-c
except KeyboardInterrupt:
print ("Program stopped by keyboard interrupt [CTRL_C] by user. ")
Thank you #AbhinavMathur for forcing me to stay on adding a try-except because in the end it’s just that I wasn’t positioning correctly in the script
This is the modif allowing the script to not crash with a connection error.
#!/usr/bin/python
# -*- coding: utf-8 -*-
import os
import glob
import argparse
import time
import datetime
import sys
from influxdb import InfluxDBClient
os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')
# add more sensor variables here based on your setup
# For multiple sensor
# temp=['sensor code','tttttttttt','ddddddddddd','ssssssssss']
temp=['0120215dbea2','0120327e05bf']
base_dir = '/sys/bus/w1/devices/'
# Ext = 28-0120215dbea2
# Int = 28-0120327e05bf
device_folders = glob.glob(base_dir + '28*')
snum=2 #Number of connected temperature sensors
# Set required InfluxDB parameters.
# (this could be added to the program args instead of beeing hard coded...)
host = "NasGrafana.lan.prive" #Could also use local ip address like "192.168.1.136"
port = 8086
user = "temperature"
password = "12345678"
# Sample period (s).
# How frequently we will write sensor data from the temperature sensors to the database.
sampling_period = 120
def read_temp_raw(device_file):
f = open(device_file, 'r')
lines = f.readlines()
f.close()
return lines
def read_temp(device_file): # checks the temp recieved for errors
lines = read_temp_raw(device_file)
while lines[0].strip()[-3:] != 'YES':
time.sleep(0.2)
lines = read_temp_raw(device_file)
equals_pos = lines[1].find('t=')
if equals_pos != -1:
temp_string = lines[1][equals_pos+2:]
# set proper decimal place for C
temp = float(temp_string) / 1000.0
# Round temp to 2 decimal points
temp = round(temp, 1)
# value of temp might be unknown here if equals_pos == -1
return temp
def get_args():
'''This function parses and returns arguments passed in'''
# Assign description to the help doc
parser = argparse.ArgumentParser(description='Program writes measurements data from the connected DS18B20 to specified influx db.')
# Add arguments
parser.add_argument(
'-db','--database', type=str, help='Database name', required=True)
parser.add_argument(
'-sn','--session', type=str, help='Session', required=True)
now = datetime.datetime.now()
parser.add_argument(
'-rn','--run', type=str, help='Run number', required=False,default=now.strftime("%Y%m%d%H%M"))
# Array of all arguments passed to script
args=parser.parse_args()
# Assign args to variables
dbname=args.database
runNo=args.run
session=args.session
return dbname, session,runNo
def get_data_points():
# Get the three measurement values from the DS18B20 sensors
for sensors in range (snum): # change number of sensors based on your setup
device_file=device_folders[sensors]+ '/w1_slave'
temp[sensors] = read_temp(device_file)
print (device_file,sensors,temp[sensors])
# Get a local timestamp
timestamp=datetime.datetime.utcnow().isoformat()
NumDevice=os.path.basename(os.path.dirname(device_file))
# Create Influxdb datapoints (using lineprotocol as of Influxdb >1.1)
datapoints = [
{
"measurement": session,
# "tags": {"runNum": NumDevice,},
"tags": {"runNum": runNo,},
"time": timestamp,
#"fields": {"temperature 1":temp[0],"temperature 2":temp[1],"temperature 3":temp[2],"temperature 4":temp[3]}
"fields": {"temperature 1":temp[0],"temperature 2":temp[1]}
}
]
return datapoints
# Match return values from get_arguments()
# and assign to their respective variables
dbname, session, runNo =get_args()
print ("Session: ", session)
print ("Run No: ", runNo)
print ("DB name: ", dbname)
# Initialize the Influxdb client
client = InfluxDBClient(host, port, user, password, dbname)
try:
while True:
# Write datapoints to InfluxDB
datapoints=get_data_points()
try:
bResult=client.write_points(datapoints)
print("Write points {0} Bresult:{1}".format(datapoints,bResult))
except:
print("Error lan connection")
#time.sleep(30)
#continue
# Wait for next sample
time.sleep(sampling_period)
# Run until keyboard ctrl-c
except KeyboardInterrupt:
print ("Program stopped by keyboard interrupt [CTRL_C] by user. ")
In this script I am taking the temperature from a DHT11 sensor and parsing the data that another script can read. Everything works except for writing the file to another pc using the path I placed in the f = open part of the script below. Everything works great except that the file doesn't get written or saved.
Any Help?
#!/usr/bin/env python
# encoding: utf-8
import sys
import time
import dht11
import RPi.GPIO as GPIO
#define GPIO 14 as DHT11 data pin
Temp_sensor=14
def main():
# Main program block
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM) # Use BCM GPIO numbers
instance = dht11.DHT11(pin = Temp_sensor)
while True:
#get DHT11 sensor value
result = instance.read()
temp = '{:.0f}'.format(result.temperature * 1.8 + 32)+"°"
# The path to send the txt file to and save is /10.1.1.28/c$/Temperature_RETR/kvoa_temp.txt
if result.is_valid():
print temp
f = open('\\10.1.1.28\c$\Temperature_RETR\new_temp.txt','w')
#f = open('/home/pi/Desktop/new_temp.txt','w')
y = temp
z = str(y)
f.write(z)
f.close()
time.sleep(60) # 60 second delay
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
pass
I am working with a Pi3, a bread board, a temp sensor and a 4-channel relay. Right now, I have two buttons on my bread board, which, when pushed are supposed to display the temperature and turn on a relay and turn of another. I am working towards building a smart thermostat so think of the buttons representing air-conditioning and heating, they cannot be on at the same time.
My issue is that, when displaying the temperature, it references the object (read_temp()), which displays the temperature correctly for one button and not the other. It will only display the very last part of equation which converts Celsius to Fahrenheit. For example, I will hit both buttons, one will display 75 degrees and the other will always display 32.
I have tried declaring the buttons differently as GPIO.inputs, I have moved to different GPIO pins thinking it is a hardware issue, I have switched the position of the buttons and I have tried returning both temp_c and temp_f in (read_temp()) object and nothing seems to do the trick.
Currently, it is the AC button that is not working properly but as I mentioned, I have switched the buttons and the pins around and it still only displays properly for one.
Thanks!
import RPi.GPIO as GPIO
import time
import os
import glob
import time
import sys
from gpiozero import Button
import pdb
# init list with pin numbers
GPIO.setmode(GPIO.BCM)
pinList = [2, 3, 27, 17]
AC = Button(12)
Heat = Button(21)
# loop through pins and set mode and state to 'high'
for i in pinList:
GPIO.setup(i, GPIO.OUT)
GPIO.output(i, GPIO.HIGH)
# time to sleep between operations in the main loop
##SleepTimeL = 5
# Setting up temperarture sensor
os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')
base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28*')[0]
device_file = device_folder + '/w1_slave'
def read_temp_raw():
f = open(device_file, 'r')
lines = f.readlines()
f.close()
return lines
def read_temp():
lines = read_temp_raw()
while lines[0].strip()[-3:] != 'YES':
time.sleep(0.2)
lines = read_temp_raw()
equals_pos = lines[1].find('t=')
if equals_pos != -1:
temp_string = lines[1][equals_pos+2:]
temp_c = float(temp_string) / 1000.0
temp_f = temp_c * 9.0 / 5.0 + 32.0
return temp_f
# main loop
try:
while True:
if AC.is_pressed:
GPIO.output(2, GPIO.LOW)
GPIO.output(3, GPIO.HIGH)
print(read_temp()), "degrees farenheit"
if Heat.is_pressed:
GPIO.output(3, GPIO.LOW)
GPIO.output(2, GPIO.HIGH)
print(read_temp()), "degrees farenheit"
except KeyboardInterrupt:
print " Quit"
GPIO.cleanup()
I'm trying to get my RPi to send temp data to Xively and I'm having a horrible time getting my code to work. This is the latest reponse I get when I run the python script...
Traceback (most recent call last):
File "xively1.py", line 11, in <module>
import xively # for Xively
File "/home/pi/xively/xively.py", line 11, in <module>
FEED_ID = os.environ["736915202"]
File "/usr/lib/python2.7/UserDict.py", line 23, in __getitem__
raise KeyError(key)
KeyError: '736915202'
Can someone explain to me what this means and what I need to do to correct? Thanks.
#!/usr/bin/env python
# This program reads two DS18B20 1-wire temperature sensors and sends the values to
# Xively https://xively.com/feeds/360495937
# tempF[0] is the reading from the outdoor tempersture sensor '28-0000059f6ece'
# tempF[1] is the reading from the indoor temperature sensor '28-0000059fa9ce'
outdoor = 0
indoor = 1
import xively # for Xively
import time
import datetime
import os # for 1-wire
import glob # for 1-wire
def read_temp_raw(): #a function that grabs the raw temperatures data from the sensors
f_1 = open(device_file[0], 'r') # first DS18B20
lines_1 = f_1.readlines()
f_1.close()
f_2 = open(device_file[1], 'r') # second DS18B20
lines_2 = f_2.readlines()
f_2.close()
return lines_1 + lines_2
def read_temp(): #a function that checks that the connections were good
lines = read_temp_raw()
while lines[0].strip()[-3:] != 'YES' or lines[2].strip()[-3:] != 'YES':
time.sleep(0.2)
lines = read_temp_raw()
equals_pos = lines[1].find('t='), lines[3].find('t=')
tempC = float(lines[1][equals_pos[0]+2:])/1000, float(lines[3] [equals_pos[1]+2:])/1000
tempF = round(tempC[0] * 9.0 / 5.0 + 32.0,1), round(tempC[1] * 9.0 / 5.0 + 32.0,1)
return tempF
def send_to_Xively(TempF):
XIVELY_FEED_ID = "736915202"
XIVELY_API_KEY = "QA6mqStQIqCFLOXtA4tzxiFpv8cqHNaYr1MFjRZdrphGwxYN"
#def send_to_Xively(TempF):
now = datetime.datetime.utcnow()
try:
print "Sending to Xively...",
xivelyapi = xively.XivelyAPIClient(XIVELY_API_KEY)
xivelyfeed = xivelyapi.feeds.get(XIVELY_FEED_ID)
xivelyfeed.datastreams = [
xively.Datastream(id='temp0', current_value=round(TempF[outdoor],1), at=now),
xively.Datastream(id='temp1', current_value=round(TempF[indoor],1), at=now)
]
xivelyfeed.update()
print "OK"
except requests.HTTPError as e:
print "HTTPError({0}): {1}".format(e.errno, e.strerror)
# this part for the 1-wire DS18S20
os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')
#set up the locations of the sensors in the system
device_folder = glob.glob('/sys/bus/w1/devices/28*')
device_file = [device_folder[0] + '/w1_slave', device_folder[1] + '/w1_slave']
# main program
TempF = read_temp()
send_to_Xively(TempF)
The xively module is expecting the environment variable "736915202" to be set. It's not, so it's throwing an exception.
That seems like a very strange environment variable to have set, though. Is /home/pi/xively/xively.py a third-party module, or did you write it? If you wrote that file, but you expected calling import xively to import a third-party module, you should rename /home/pi/xively/xively.py to something else, and that will probably fix your problem.
public class AnimalPrinter
{
public void printDog()
{
System.out.println("dog");
}
public void printCat()
{
System.out.println("cat");
}
/* constructors not shown */
}