Skip to content

Commit

Permalink
Merge pull request #4 from Honey-Pi/develop
Browse files Browse the repository at this point in the history
added offline measurement and a lot of improvements
  • Loading branch information
JavanXD authored Apr 24, 2019
2 parents 9ec17ed + ecd3030 commit b05f449
Show file tree
Hide file tree
Showing 11 changed files with 153 additions and 81 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ error.log
# =========================
*.pyc
error.log
*.csv
44 changes: 22 additions & 22 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
import threading
import time

import RPi.GPIO as GPIO
import RPi.GPIO as GPIO

from read_and_upload_all import start_measurement
from read_settings import get_settings
from utilities import stop_tv, stop_led, start_led, error_log, reboot, client_to_ap_mode, ap_to_client_mode, blink_led
from utilities import stop_tv, stop_led, start_led, error_log, reboot, client_to_ap_mode, ap_to_client_mode, blink_led, miliseconds

# global vars
measurement = None
Expand All @@ -19,23 +19,24 @@
debug = 0 # will be overriten by settings.json. you need to change the debug-mode in settings.json
time_start = 0 # will be set by button_pressed event if the button is rised
GPIO_LED = 21 # GPIO for led
gpio = 17 # gpio for button, will be overwritten by settings.json
gpio = 16 # gpio for button, will be overwritten by settings.json

def start_ap():
global isActive, GPIO_LED
isActive = 1 # measurement shall start next time
print("AccessPoint start")
print("Maintenance Mode: START - Connect yourself to HoneyPi-Wifi.")
start_led()
GPIO.output(GPIO_LED, GPIO.HIGH)
GPIO.output(GPIO_LED, GPIO.HIGH)
t1 = threading.Thread(target=client_to_ap_mode) #client_to_ap_mode()
t1.start()

def stop_ap(boot=0):
global isActive, GPIO_LED
isActive = 0 # measurement shall stop next time
print("AccessPoint stop")
if not boot:
print("Maintenance Mode: STOP")
stop_led()
GPIO.output(GPIO_LED, GPIO.LOW)
GPIO.output(GPIO_LED, GPIO.LOW)
t2 = threading.Thread(target=ap_to_client_mode) #ap_to_client_mode()
t2.start()

Expand All @@ -48,14 +49,13 @@ def close_script():

def toggle_measurement():
global isActive, measurement_stop, measurement
print("Button was pressed")
if isActive == 0:
print("Button: Stop measurement")
print("Button was pressed: Stop measurement")
# stop the measurement by event's flag
measurement_stop.set()
start_ap() # finally start AP
else:
print("Button: Start measurement")
print("Button was pressed: Start measurement")
if measurement.is_alive():
print("Warning: Thread should not be active anymore")
measurement_stop.clear() # reset flag
Expand All @@ -66,22 +66,22 @@ def toggle_measurement():

def button_pressed(channel):
global gpio
if GPIO.input(gpio): # if port == 1
button_pressed_rising()
else: # if port != 1
button_pressed_falling()
if GPIO.input(gpio): # if port == 1
button_pressed_rising()
else: # if port != 1
button_pressed_falling()

def button_pressed_rising():
global time_start
time_start = time.time()
time_start = miliseconds()

def button_pressed_falling():
global time_start, debug
time_end = time.time()
time_end = miliseconds()
time_elapsed = time_end-time_start
MIN_SECONDS_TO_ELAPSE = 1 # seconds
MAX_SECONDS_TO_ELAPSE = 3
if time_elapsed >= MIN_SECONDS_TO_ELAPSE and time_elapsed <= MAX_SECONDS_TO_ELAPSE:
MIN_TIME_TO_ELAPSE = 500 # miliseconds
MAX_TIME_TO_ELAPSE = 3000
if time_elapsed >= MIN_TIME_TO_ELAPSE and time_elapsed <= MAX_TIME_TO_ELAPSE:
time_start = 0 # reset to prevent multiple fallings from the same rising
toggle_measurement()
elif debug:
Expand All @@ -104,13 +104,13 @@ def main():

# by default is AccessPoint down
stop_ap(1)

debug = settings["debug"] # flag to enable debug mode (HDMI output enabled and no rebooting)
if not debug:
# stop HDMI power (save energy)
print("Shutting down HDMI to save engery.")
stop_tv()

# start as seperate background thread
# because Taster pressing was not recognised
measurement_stop = threading.Event() # create event to stop measurement
Expand Down Expand Up @@ -139,4 +139,4 @@ def main():
error_log(e, "Unhandled Exception in Main")
if not debug:
time.sleep(60)
reboot()
reboot()
102 changes: 57 additions & 45 deletions read_and_upload_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from read_max import measure_tc
from read_settings import get_settings, get_sensors
from utilities import reboot, error_log, shutdown
from write_csv import write_csv

class MyRebootException(Exception):
"""Too many ConnectionErrors => Rebooting"""
Expand All @@ -37,6 +38,7 @@ def start_measurement(measurement_stop):
interval = settings["interval"]
debug = settings["debug"] # flag to enable debug mode (HDMI output enabled and no rebooting)
shutdownAfterTransfer = settings["shutdownAfterTransfer"]
offline = settings["offline"] # flag to enable offline csv storage

if debug:
print("Debug-Mode is enabled.")
Expand Down Expand Up @@ -74,29 +76,29 @@ def start_measurement(measurement_stop):

# start at -6 because we want to get 6 values before we can filter some out
counter = -6
time_measured = 0
while not measurement_stop.is_set():
counter += 1

# read values from sensors every second
for (sensorIndex, sensor) in enumerate(ds18b20Sensors):
checkIfSensorExistsInArray(sensorIndex)
if 'device_id' in sensor:
read_unfiltered_temperatur_values(sensorIndex, sensor['device_id'])

# for testing:
#try:
# weight = measure_weight(weightSensors[0])
# print("weight: " + str(list(weight.values())[0]))
#except IOError:
# print "IOError occurred"
#except TypeError:
# print "TypeError occurred"
#except IndexError:
# print "IndexError occurred"

# wait seconds of interval before next check
# free ThingSpeak account has an upload limit of 15 seconds
if counter%interval == 0 or interval == 1:
print("Time over for a new measurement.")
time_now = time.time()
isTimeToMeasure = (time_now-time_measured >= interval) and counter > 0 # old: counter%interval == 0
if isTimeToMeasure or interval == 1:
now = time.strftime("%H:%M", time.localtime(time_now))
lastMeasurement = time.strftime("%H:%M", time.localtime(time_measured))
if time_measured == 0:
print("First time measurement. Now: " + str(now))
else:
print("Last measurement was at " + str(lastMeasurement))
print("Time over for a new measurement. Time is now: " + str(now))
time_measured = time.time()

# filter the values out
for (sensorIndex, sensor) in enumerate(ds18b20Sensors):
Expand Down Expand Up @@ -136,38 +138,49 @@ def start_measurement(measurement_stop):
ts_fields.update(weight)

# print all measurement values stored in ts_fields
try:
# python2
for key, value in ts_fields.iteritems():
print(key + ": " + str(value))
except AttributeError:
# python3
for key, value in ts_fields.items():
print(key + ": " + str(value))

try:
# update ThingSpeak / transfer values
if len(ts_fields) > 0:
channel.update(ts_fields)
if debug:
error_log("Info: Data succesfully transfered to ThingSpeak.")
if connectionErros > 0:
for key, value in ts_fields.items():
print(key + ": " + str(value))

if len(ts_fields) > 0:
if offline == 1 or offline == 3:
try:
write_csv(ts_fields)
if debug:
error_log("Info: Connection Errors (" + str(connectionErros) + ") Counting resetet.")
# reset connectionErros because transfer succeded
connectionErros = 0
except requests.exceptions.HTTPError as errh:
error_log(errh, "Http Error")
except requests.exceptions.ConnectionError as errc:
error_log(errc, "Error Connecting " + str(connectionErros))
connectionErros += 1
# multiple connectionErrors in a row => Exception
if connectionErros >= 5:
raise MyRebootException
except requests.exceptions.Timeout as errt:
error_log(errt, "Timeout Error")
except requests.exceptions.RequestException as err:
error_log(err, "Something Else")
error_log("Info: Data succesfully saved to CSV-File.")
except Exception as ex:
error_log(ex, "Exception")
if offline == 0 or offline == 1 or offline == 2:
try:
# update ThingSpeak / transfer values
channel.update(ts_fields)
if debug:
error_log("Info: Data succesfully transfered to ThingSpeak.")
if connectionErros > 0:
if debug:
error_log("Info: Connection Errors (" + str(connectionErros) + ") Counting resetet.")
# reset connectionErros because transfer succeded
connectionErros = 0
except requests.exceptions.HTTPError as errh:
error_log(errh, "Http Error")
except requests.exceptions.ConnectionError as errc:
error_log(errc, "Error Connecting " + str(connectionErros))
connectionErros += 1

# Write to CSV-File if ConnectionError
if offline == 2:
write_csv(ts_fields)
if debug:
error_log("Info: Data succesfully saved to CSV-File.")

# multiple connectionErrors in a row => MyRebootException
if connectionErros >= 5:
raise MyRebootException
except requests.exceptions.Timeout as errt:
error_log(errt, "Timeout Error")
except requests.exceptions.RequestException as err:
error_log(err, "Something Else")
except Exception as exTs:
error_log(exTs, "ThingSpeak Exception")

# stop measurements after uploading once
if interval == 1:
Expand All @@ -179,7 +192,6 @@ def start_measurement(measurement_stop):
sleep(10)
shutdown()

counter += 1
sleep(0.96)

end_time = time.time()
Expand Down
2 changes: 1 addition & 1 deletion read_hx711.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# This file is part of HoneyPi [honey-pi.de] which is released under Creative Commons License Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0).
# See file LICENSE or go to http://creativecommons.org/licenses/by-nc-sa/3.0/ for full license details.

from HX711 import HX711
from sensors.HX711 import HX711
import RPi.GPIO as GPIO
import time

Expand Down
10 changes: 5 additions & 5 deletions read_max.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
# This file is part of HoneyPi [honey-pi.de] which is released under Creative Commons License Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0).
# See file LICENSE or go to http://creativecommons.org/licenses/by-nc-sa/3.0/ for full license details.

from MAX6675 import MAX6675
from MAX31855 import MAX31855
from sensors.MAX6675 import MAX6675
from sensors.MAX31855 import MAX31855
import RPi.GPIO as GPIO

def measure_tc(tc_sensor):
Expand All @@ -20,7 +20,7 @@ def measure_tc(tc_sensor):
except Exception as e:
print("MAX6675/MAX31855 missing param: " + str(e))

tc_temperature = 0
tc_temperature = None

# setup tc-Sensor
try:
Expand All @@ -46,6 +46,6 @@ def measure_tc(tc_sensor):
except Exception as e:
print("Reading MAX6675/MAX31855 failed: " + str(e))

if 'ts_field' in tc_sensor:
if 'ts_field' in tc_sensor and tc_temperature is not None:
return ({tc_sensor["ts_field"]: tc_temperature})
return {}
return {}
9 changes: 7 additions & 2 deletions read_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def get_settings():
my_abs_path = my_file.resolve()
except OSError: # FileNotFoundError
# doesn"t exist => default values
settings["button_pin"] = 17
settings["button_pin"] = 16
settings["interval"] = 300

else:
Expand All @@ -34,7 +34,7 @@ def check_vars(settings):
if not settings["button_pin"]:
raise Exception("button_pin is not defined.")
except:
settings["button_pin"] = 17
settings["button_pin"] = 16

try:
if not 'debug' in settings:
Expand All @@ -55,6 +55,11 @@ def check_vars(settings):
settings["ts_channel_id"] = None
settings["ts_write_key"] = None

try:
settings["offline"]
except KeyError:
settings["offline"] = 0

return settings

# get sensors by type
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
30 changes: 24 additions & 6 deletions utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ def client_to_ap_mode():
# Enable static ip
os.system("sudo mv /etc/dhcpcd.conf.disabled /etc/dhcpcd.conf")
# Restart DHCP server for IP Address
os.system("sudo service dhcpcd restart && systemctl daemon-reload") # & will execute command in the background
os.system("sudo systemctl restart dhcpcd.service && sudo systemctl daemon-reload") # & will execute command in the background
# restart AP Services
os.system("sudo systemctl restart dnsmasq.service")
os.system("sudo systemctl restart hostapd.service || (systemctl unmask hostapd && systemctl enable hostapd && systemctl start hostapd)") # if restart fails because service is masked => unmask
os.system("sudo systemctl restart hostapd.service || (systemctl unmask hostapd && systemctl enable hostapd && systemctl start hostapd) &") # if restart fails because service is masked => unmask
start_wlan()

def ap_to_client_mode():
Expand All @@ -62,7 +62,7 @@ def ap_to_client_mode():
# Disable static ip
os.system("sudo mv /etc/dhcpcd.conf /etc/dhcpcd.conf.disabled")
# Restart DHCP server for IP Address
os.system("sudo service dhcpcd restart && systemctl daemon-reload") # & will execute command in the background
os.system("sudo systemctl restart dhcpcd.service && sudo systemctl daemon-reload") # & will execute command in the background
# Start WPA Daemon
os.system("sudo wpa_supplicant -i wlan0 -D wext -c /etc/wpa_supplicant/wpa_supplicant.conf -B")
# activate the wifi connection with Id=0
Expand All @@ -75,12 +75,30 @@ def reboot():
def shutdown():
os.system("sudo shutdown -h 0")

def miliseconds():
return int(round(time.time() * 1000))

# reduce size if file is to big
def check_file(file, size=5, entries=25, skipFirst=0):
try:
# If bigger than 5MB
if os.path.getsize(file) > size * 1024:
readFile = open(file)
lines = readFile.readlines()
readFile.close()
w = open(file,'w')
# delete first 25 lines in file
# When CSV: skip first entry because it is header (skipFirst=1)
del lines[skipFirst:entries]
w.writelines(lines)
w.close()
except FileNotFoundError:
pass

def error_log(e=None, printText=None):
try:
file = scriptsFolder + '/error.log'
# reset file if to big
if os.path.getsize(file) > 100 * 1024:
os.remove(file)
check_file(file) # reset file if it gets to big

# generate printed text
if printText and e:
Expand Down
Loading

0 comments on commit b05f449

Please sign in to comment.