From 00699d40a58725e9775cb787eb6cf7cce66132b5 Mon Sep 17 00:00:00 2001 From: Angelo V Date: Sat, 15 Dec 2018 20:05:08 +0100 Subject: [PATCH] Fixed some issues --- Prepare for Release/Release checklist | 1 + SchedulerMod.py | 19 +- autowateringmod.py | 8 +- bash/install_hydrosys4.sh | 2 + bash/install_hydrosys4v21.sh | 757 ++++++++++++++++++++++++++ changelog/change | 2 + networkmod.py | 2 +- selectedplanmod.py | 88 ++- sensordbmod.py | 1 - start.py | 67 +-- templates/showsensordata.html | 8 +- wpa_cli_mod.py | 5 +- 12 files changed, 879 insertions(+), 81 deletions(-) create mode 100644 bash/install_hydrosys4v21.sh diff --git a/Prepare for Release/Release checklist b/Prepare for Release/Release checklist index 4335443..cee7268 100644 --- a/Prepare for Release/Release checklist +++ b/Prepare for Release/Release checklist @@ -5,6 +5,7 @@ OPERATING SYSTEM LEVEL: 1) disable SSH -> sudo raspi-config -> advanced -> disable SSH server 2) Check wifi password (AP mode) is "hydrosystem"-> sudo nano /etc/hostapd/hostapd.conf 4) check that the wifi account is deleted -> nano /etc/wpa_supplicant/wpa_supplicant.conf +5) set ownership of the files: sudo chown -R $USER ~/env/autonomMaster2 HYDROSYSTEM SW LEVEL: diff --git a/SchedulerMod.py b/SchedulerMod.py index 57076f5..fdb2f37 100644 --- a/SchedulerMod.py +++ b/SchedulerMod.py @@ -6,6 +6,7 @@ import apscheduler from apscheduler.schedulers.background import BackgroundScheduler +logger = logging.getLogger("hydrosys4."+__name__) # The "apscheduler." prefix is hard coded @@ -25,29 +26,27 @@ - -logger = logging.getLogger("hydrosys4."+__name__) - - - - def print_job(): global sched - sched.print_jobs() + sched.print_jobs() + return True def start_scheduler(): global sched - sched.start() + sched.start() + return True def removealljobs(): global sched for job in sched.get_jobs(): - job.remove() + job.remove() + return True def stop_scheduler(): global sched if sched.running: - sched.shutdown(wait=False) + sched.shutdown(wait=False) + return True def get_next_run_time(jobname): global sched diff --git a/autowateringmod.py b/autowateringmod.py index 792279f..3d22e53 100644 --- a/autowateringmod.py +++ b/autowateringmod.py @@ -315,13 +315,15 @@ def autowateringexecute(refsensor,element): # implment alert message for the cycle exceeding days, and reset the cycle if workmode!="None": - if sensordbmod.timediffdays(datetime.now(),AUTO_data[element]["cyclestartdate"]) > maxdays: + timedeltadays=sensordbmod.timediffdays(datetime.now(),AUTO_data[element]["cyclestartdate"]) + if (timedeltadays > maxdays): #the upper limit is set in case of abrupt time change textmessage="WARNING "+ sensor + " watering cycle is taking too many days, watering system: " + element + ". Reset watering cycle" print textmessage # in case of full Auto, activate pump for minimum pulse period if workmode=="Full Auto": - textmessage="WARNING "+ sensor + " watering cycle is taking too many days, watering system: " + element + ". Activate Min pulse + Reset watering cycle" - activatewater(element, duration) + if (timedeltadays < maxdays+2): #the upper limit is set in case of abrupt time change + textmessage="WARNING "+ sensor + " watering cycle is taking too many days, watering system: " + element + ". Activate Min pulse + Reset watering cycle" + activatewater(element, duration) #send alert mail notification if mailtype!="warningonly": emailmod.sendallmail("alert", textmessage) diff --git a/bash/install_hydrosys4.sh b/bash/install_hydrosys4.sh index ea24bc5..8a9e25b 100644 --- a/bash/install_hydrosys4.sh +++ b/bash/install_hydrosys4.sh @@ -147,9 +147,11 @@ if [ "$autostart" == "yes" ]; then sudo iptables-restore < /home/pi/iptables.rules # clock +echo "HYDROSYS4-set HW clock ****************************************" echo ds3231 0x68 > /sys/class/i2c-adapter/i2c-1/new_device || true hwclock -s || true +echo "HYDROSYS4-start system ****************************************" cd /home/pi/env/autonom/ sudo python /home/pi/env/autonom/bentornado.py & diff --git a/bash/install_hydrosys4v21.sh b/bash/install_hydrosys4v21.sh new file mode 100644 index 0000000..8a9e25b --- /dev/null +++ b/bash/install_hydrosys4v21.sh @@ -0,0 +1,757 @@ +#!/bin/bash + + +#Debug enable next 3 lines +exec 5> install.txt +BASH_XTRACEFD="5" +set -x +# ------ end debug + + +function killpython() +{ + +sudo killall python + +} + + +function system_update_light() +{ + +# ---- system_update + +sudo apt-get -y update + +} + +function system_update() +{ + +# ---- remove unnecessary packages + +sudo apt-get remove --purge libreoffice-* +sudo apt-get remove --purge wolfram-engine + + +# ---- system_update + +sudo apt-get -y update +sudo apt-get -y upgrade + +} + +function system_update_UI() +{ + +while true; do + read -p "Do you wish to update the Raspbian system (y/n)?" yn + case $yn in + [Yy]* ) system_update; break;; + [Nn]* ) break;; + * ) echo "Please answer y or n.";; + esac +done + +} + +function install_dependencies() +{ + + +#--- start installing dependencies + +sudo apt-get -y install python-dev || { echo "ERROR --------------------------Installation failed ----------------" && exit ;} +sudo apt-get -y install python-pip || { echo "ERROR --------------------------Installation failed ----------------" && exit ;} +sudo pip install flask || { echo "ERROR --------------------------Installation failed ----------------" && exit ;} +sudo pip install apscheduler || { echo "ERROR --------------------------Installation failed ----------------" && exit ;} +sudo pip install pyserial || { echo "ERROR --------------------------Installation failed ----------------" && exit ;} + +#(for the webcam support) +sudo apt-get -y install fswebcam || { echo "ERROR --------------------------Installation failed ----------------" && exit ;} + +#(for the image thumbnail support) +sudo apt-get -y install libjpeg-dev || { echo "ERROR --------------------------Installation failed ----------------" && exit ;} +sudo pip install Pillow || { echo "ERROR --------------------------Installation failed ----------------" && exit ;} + +#(for external IP address, using DNS) +sudo apt-get -y install dnsutils || { echo "ERROR --------------------------Installation failed ----------------" && exit ;} + +#(encryption) +sudo pip install pbkdf2 || { echo "ERROR --------------------------Installation failed ----------------" && exit ;} + +#(web server) +sudo pip install tornado || { echo "ERROR --------------------------Installation failed ----------------" && exit ;} + +} + +function enable_I2C() +{ + +# --- Enable I2C and Spi : +# /boot/config.txt + +sed -i 's/\(^.*#dtparam=i2c_arm=on.*$\)/dtparam=i2c_arm=on/' /boot/config.txt +sed -i 's/\(^.*#dtparam=spi=on.*$\)/dtparam=spi=on/' /boot/config.txt +sed -i 's/\(^.*#dtparam=i2s=on.*$\)/dtparam=i2s=on/' /boot/config.txt + +# --- Add modules: +# /etc/modules +aconf="/etc/modules" + +sed -i '/i2c-bcm2708/d' $aconf +sed -i -e "\$ai2c-bcm2708" $aconf + +sed -i '/i2c-dev/d' $aconf +sed -i -e "\$ai2c-dev" $aconf + +sed -i '/i2c-bcm2835/d' $aconf +sed -i -e "\$ai2c-bcm2835" $aconf + +sed -i '/rtc-ds1307/d' $aconf +sed -i -e "\$artc-ds1307" $aconf + +sed -i '/bcm2835-v4l2/d' $aconf +sed -i -e "\$abcm2835-v4l2" $aconf + + +# --- install I2C tools +sudo apt-get -y install git build-essential python-dev python-smbus || { echo "ERROR --------------------------Installation failed ----------------" && exit ;} +sudo apt-get -y install -y i2c-tools || { echo "ERROR --------------------------Installation failed ----------------" && exit ;} + +} + + +# --- enable raspicam + +############# MISSING ############## + +function modify_RClocal() +{ + +# --- Real Time Clock (RTC) +# /etc/rc.local + +autostart="yes" +# copy the below lines between # START and #END to rc.local +tmpfile=$(mktemp) +sudo sed '/#START/,/#END/d' /etc/rc.local > "$tmpfile" && sudo mv "$tmpfile" /etc/rc.local +# Remove to growing plank lines. +sudo awk '!NF {if (++n <= 1) print; next}; {n=0;print}' /etc/rc.local > "$tmpfile" && sudo mv "$tmpfile" /etc/rc.local +if [ "$autostart" == "yes" ]; then + if ! grep -Fq '#START HYDROSYS4 SECTION' /etc/rc.local; then + sudo sed -i '/exit 0/d' /etc/rc.local + sudo bash -c "cat >> /etc/rc.local" << EOF +#START HYDROSYS4 SECTION +# iptables +sudo iptables-restore < /home/pi/iptables.rules + +# clock +echo "HYDROSYS4-set HW clock ****************************************" +echo ds3231 0x68 > /sys/class/i2c-adapter/i2c-1/new_device || true +hwclock -s || true + +echo "HYDROSYS4-start system ****************************************" +cd /home/pi/env/autonom/ +sudo python /home/pi/env/autonom/bentornado.py & + +#END HYDROSYS4 SECTION + +exit 0 +EOF + else + tmpfile=$(mktemp) + sudo sed '/#START/,/#END/d' /etc/rc.local > "$tmpfile" && sudo mv "$tmpfile" /etc/rc.local + # Remove to growing plank lines. + sudo awk '!NF {if (++n <= 1) print; next}; {n=0;print}' /etc/rc.local > "$tmpfile" && sudo mv "$tmpfile" /etc/rc.local + fi + +fi + +sudo chown root:root /etc/rc.local +sudo chmod 755 /etc/rc.local +# end modification to RC.local + +} + + +### -- WIFI setup --- STANDARD + +function valid_ip() +{ + local ip=$1 + local stat=1 + + if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then + OIFS=$IFS + IFS='.' + ip=($ip) + IFS=$OIFS + [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \ + && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]] + stat=$? + fi + return $stat +} + + +input_UI () +{ + +echo "Hello, following initial setting is requested:" + +# IP part input + +IP="0" +while ! valid_ip $IP; do + read -p "Local IP address (range 192.168.0.100-192.168.1.200), to confirm press [ENTER] or modify: " -e -i 192.168.1.172 IP + if valid_ip $IP; then stat='good'; + else stat='bad'; echo "WRONG FORMAT, please enter a valid value for IP address" + fi + +done + echo "Confirmed IP address: "$IP + +PORT="" +while [[ ! $PORT =~ ^[0-9]+$ ]]; do +read -p "Local PORT, to confirm press [ENTER] or modify: " -e -i 5172 PORT + if [[ ! $PORT =~ ^[0-9]+$ ]]; + then echo "WRONG FORMAT, please enter a valid value for PORT"; + fi +done + echo "Confirmed PORT: "$PORT + +# Local WiFi AP name and password setting + +read -p "System WiFi AP name, to confirm press [ENTER] or modify: " -e -i Hydrosys4 WiFiAPname +echo "Confirmed Name: "$WiFiAPname + +read -p "System WiFi AP password, to confirm press [ENTER] or modify: " -e -i hydrosystem WiFiAPpsw +echo "Confirmed Password: "$WiFiAPpsw + +} + +install_MotorShieldlib () +{ + +# --- installing the python dev-library +sudo apt-get -y install build-essential python-dev || { echo "ERROR --------------------------Installation failed ----------------" && exit ;} + +# check if file exist in local folder +aconf="/home/pi/env/autonom/libraries/MotorHat/master.zip" +if [ -f $aconf ]; then + cd /home/pi/env/autonom/libraries/MotorHat + unzip master.zip + cd Adafruit-Motor-HAT-Python-Library-master + sudo python setup.py install + cd /home/pi +else + cd /home/pi + sudo rm -r MotorHat + mkdir MotorHat + cd MotorHat + wget https://github.com/adafruit/Adafruit-Motor-HAT-Python-Library/archive/master.zip + unzip master.zip + cd Adafruit-Motor-HAT-Python-Library-master + sudo python setup.py install + cd /home/pi +fi +} + + + + +install_DHT22lib () +{ + +# --- installing the DHT22 Sensor libraries +sudo apt-get -y install build-essential python-dev || { echo "ERROR --------------------------Installation failed ----------------" && exit ;} + +# check if file exist in local folder +aconf="/home/pi/env/autonom/libraries/DHT22/master.zip" +if [ -f $aconf ]; then + + cd /home/pi/env/autonom/libraries/DHT22 + unzip master.zip + cd Adafruit_Python_DHT-master + # setup1plus is file that try to make the DTH22 work with both RaspberryPi zero,1 and model 2,3 + sudo python setup1plus.py install + cd /home/pi +else + cd /home/pi + sudo rm -r DHT22 + mkdir DHT22 + cd DHT22 + wget https://github.com/adafruit/Adafruit_Python_DHT/archive/master.zip + unzip master.zip + cd Adafruit_Python_DHT-master + sudo python setup.py install + cd /home/pi +fi +} + + +install_SPIlib () +{ + + +# --- INSTALL SPI library: + +sudo apt-get -y install python2.7-dev || { echo "ERROR --------------------------Installation failed ----------------" && exit ;} + +# check if file exist in local folder +aconf="/home/pi/env/autonom/libraries/SPI/master.zip" +if [ -f $aconf ]; then + + cd /home/pi/env/autonom/libraries/SPI + unzip master.zip + cd py-spidev-master + sudo python setup.py install + cd /home/pi +else + +cd /home/pi +sudo rm -r SPIDEV +mkdir SPIDEV +cd SPIDEV + +wget https://github.com/Gadgetoid/py-spidev/archive/master.zip + +unzip master.zip + +rm master.zip + +cd py-spidev-master + +sudo python setup.py install + +cd .. +cd .. + +fi +} + + +install_BMPlib () +{ + +# --- INSTALL BMP180 library (pressure sensor) + +sudo apt-get -y install build-essential python-dev python-smbus || { echo "ERROR --------------------------Installation failed ----------------" && exit ;} + + +# check if file exist in local folder +aconf="/home/pi/env/autonom/libraries/BMP/master.zip" +if [ -f $aconf ]; then + + cd /home/pi/env/autonom/libraries/BMP + unzip master.zip + cd Adafruit_Python_BMP-master + sudo python setup.py install + cd /home/pi +else + +cd /home/pi +sudo rm -r bmp180 +sudo mkdir bmp180 +cd bmp180 +wget https://github.com/adafruit/Adafruit_Python_BMP/archive/master.zip +cd Adafruit_Python_BMP-master +sudo python setup.py install +cd .. +cd .. + +fi +} + + +install_hydrosys4 () +{ +# --- INSTALL Hydrosys4 software +sudo apt-get -y install git || { echo "ERROR --------------------------Installation failed ----------------" && exit ;} + + +# check if file exist in local folder +aconf="/home/pi/env/autonom" +if [ -d $aconf ]; then # if the directory exist + cd /home/pi +else + cd /home/pi + sudo rm -r env + mkdir env + cd env + sudo rm -r autonom + git clone https://github.com/Hydrosys4/Master.git + sudo killall python + mv Master autonom + cd .. + +fi + +} + + + + + + +fn_hostapd () +{ + +sudo apt-get -y install hostapd || { echo "ERROR --------------------------Installation failed ----------------" && exit ;} + + +# create hostapd.conf file +aconf="/etc/hostapd/hostapd.conf" +if [ -f $aconf ]; then + cp $aconf $aconf.1 + sudo rm $aconf + echo "remove file" +fi + + +sudo bash -c "cat >> $aconf" << EOF +# HERE-> {"name": "IPsetting", "LocalIPaddress": "$IP", "LocalPORT": "$PORT", "LocalAPSSID" : "$WiFiAPname"} +ieee80211n=1 +interface=wlan0 +ssid=$WiFiAPname +hw_mode=g +channel=6 +macaddr_acl=0 +auth_algs=1 +ignore_broadcast_ssid=0 +wpa=2 +wpa_passphrase=$WiFiAPpsw +wpa_key_mgmt=WPA-PSK +wpa_pairwise=TKIP +rsn_pairwise=CCMP +EOF + + +aconf="/etc/init.d/hostapd" +# Update hostapd main config file +sudo sed -i "s/\(^.*DAEMON_CONF=.*$\)/DAEMON_CONF=\/etc\/hostapd\/hostapd.conf/" $aconf + +sudo systemctl enable hostapd.service + +} + + +fn_dnsmasq () +{ + +sudo apt-get -y install dnsmasq || { echo "ERROR --------------------------Installation failed ----------------" && exit ;} + + +# edit /etc/dnsmasq.conf file +aconf="/etc/dnsmasq.conf" + +# delete rows between #START and #END +sed -i '/^#START HYDROSYS4 SECTION/,/^#END HYDROSYS4 SECTION/{/^#START HYDROSYS4 SECTION/!{/^#END HYDROSYS4 SECTION/!d}}' $aconf +sed -i '/#START HYDROSYS4 SECTION/d' $aconf +sed -i '/#END HYDROSYS4 SECTION/d' $aconf + +# calculation of the range starting from assigned IP address +IFS="." read -a a <<< $IP +IFS="." read -a b <<< 0.0.0.1 +IFS="." read -a c <<< 0.0.0.9 +IPSTART="$[a[0]].$[a[1]].$[a[2]].$[a[3]+b[3]]" +IPEND="$[a[0]].$[a[1]].$[a[2]].$[a[3]+c[3]]" +if [[ a[3] -gt 244 ]]; then +IPSTART="$[a[0]].$[a[1]].$[a[2]].$[a[3]-c[3]]" +IPEND="$[a[0]].$[a[1]].$[a[2]].$[a[3]-b[3]]" +fi + +echo $IPSTART $IPEND + + + +# ----- + + + +sudo bash -c "cat >> $aconf" << EOF +#START HYDROSYS4 SECTION +interface=wlan0 +dhcp-range=$IPSTART,$IPEND,12h +#no-resolv +#END HYDROSYS4 SECTION +EOF + +sudo systemctl enable dnsmasq.service + + +} + + +fn_dhcpcd () +{ + +# edit /etc/dnsmasq.conf file +aconf="/etc/dhcpcd.conf" + +# delete rows between #START and #END +sed -i '/^#START HYDROSYS4 SECTION/,/^#END HYDROSYS4 SECTION/{/^#START HYDROSYS4 SECTION/!{/^#END HYDROSYS4 SECTION/!d}}' $aconf +sed -i '/#START HYDROSYS4 SECTION/d' $aconf +sed -i '/#END HYDROSYS4 SECTION/d' $aconf + + +sudo bash -c "cat >> $aconf" << EOF +#START HYDROSYS4 SECTION +profile static_wlan0 +static ip_address=$IP/24 +#static routers=192.168.1.1 +#static domain_name_servers=192.169.1.1 +# fallback to static profile on wlan0 +interface wlan0 +fallback static_wlan0 +#END HYDROSYS4 SECTION +EOF + + +} + +fn_ifnames () +{ +# this is to preserve the network interfaces names, becasue staring from debian stretch (9) the ifnames have new rules +# edit /etc/dnsmasq.conf file +aconf="/boot/cmdline.txt" + +APPEND=' net.ifnames=0' +echo "$(cat $aconf)$APPEND" > $aconf + +} + + + + + + + + + +install_mjpegstr () +{ +cd /home/pi + +sudo rm -r mjpg-streamer + +sudo apt-get -y install cmake libjpeg8-dev git + +sudo git clone https://github.com/jacksonliam/mjpg-streamer.git + +cd mjpg-streamer/mjpg-streamer-experimental + +sudo make + +sudo make install + +cd .. +cd .. + +} + + + +install_nginx () +{ +# this function is not used anymore +cd /home/pi + +sudo apt-get -y install nginx + +# create default file +aconf="/etc/nginx/sites-enabled/default" +if [ -f $aconf ]; then + cp $aconf /home/pi/$aconf.1 + sudo rm $aconf + echo "remove file" +fi + + +sudo bash -c "cat >> $aconf" << EOF +server { + # for a public HTTP server: + listen $PORT; + server_name localhost hydrosys4.local; + + access_log off; + error_log off; + + location / { + proxy_pass http://127.0.0.1:5020; + } + + location /stream { + rewrite ^/stream(.*) /$1 break; + proxy_pass http://127.0.0.1:5022; + proxy_buffering off; + } + + location /favicon.ico { + alias /home/pi/env/autonom/static/favicon.ico; + } +} +EOF + +sudo service nginx start + +cd .. +cd .. + +} + + +install_squid3 () +{ +# this function is used to install the squid3 program used as reverse proxy +cd /home/pi + +sudo apt-get install squid3 -y || { echo "ERROR --------------------------Installation failed ----------------" && exit ;} + +# add configuration to squid.conf, the file should already exist if installation is succesful +adir="/etc/squid3" +if [ -d $adir ]; then + aconf="/etc/squid3/squid.conf" +fi +adir="/etc/squid" +if [ -d $adir ]; then + aconf="/etc/squid/squid.conf" +fi + +if [ -f $aconf ]; then + cp $aconf $aconf.1 + sudo rm $aconf + echo "remove file" +fi + + + +sudo bash -c "cat >> $aconf" << EOF +# hydrosys4 configurations + +http_port $PORT accel defaultsite=hydrosys4 vhost + +acl Safe_ports port $PORT # unregistered ports + +acl videostream urlpath_regex \?action=stream + +cache_peer localhost parent 5020 0 no-query originserver name=server1 +cache_peer_access server1 deny videostream + +cache_peer localhost parent 5022 0 no-query originserver name=server2 +cache_peer_access server2 allow videostream +cache_peer_access server2 deny all + +http_access allow Safe_ports + +# default configurations + +# WELCOME TO SQUID 3.5.12 +acl SSL_ports port 443 +acl Safe_ports port 80 # http +acl Safe_ports port 21 # ftp +acl Safe_ports port 443 # https +acl Safe_ports port 70 # gopher +acl Safe_ports port 210 # wais +acl Safe_ports port 1025-65535 # unregistered ports +acl Safe_ports port 280 # http-mgmt +acl Safe_ports port 488 # gss-http +acl Safe_ports port 591 # filemaker +acl Safe_ports port 777 # multiling http +acl CONNECT method CONNECT +http_access deny !Safe_ports +http_access deny CONNECT !SSL_ports +http_access allow localhost manager +http_access deny manager +http_access allow localhost +http_access deny all +coredump_dir /var/spool/squid +refresh_pattern ^ftp: 1440 20% 10080 +refresh_pattern ^gopher: 1440 0% 1440 +refresh_pattern -i (/cgi-bin/|\?) 0 0% 0 +refresh_pattern (Release|Packages(.gz)*)$ 0 20% 2880 +refresh_pattern . 0 20% 4320 +EOF + +sudo service squid3 start + +cd .. +cd .. + +} + + + +edit_defaultnetworkdb () +{ + + +aconf="/home/pi/env/autonom/database/default/defnetwork.txt " + +# if file already exist then no action, otherwise create it +if [ -f $aconf ]; then + echo "network default file already exist" + else + sudo bash -c "cat >> $aconf" << EOF +{"name": "IPsetting", "LocalIPaddress": "192.168.0.172", "LocalPORT": "5012" , "LocalAPSSID" : "Hydrosys4"} +EOF + +fi + +} + +edit_networkdb () +{ + + +aconf="/home/pi/env/autonom/database/network.txt " + +# if file already exist then delete it +if [ -f $aconf ]; then + sudo rm $aconf + echo "remove file" +fi + +sudo bash -c "cat >> $aconf" << EOF +{"name": "IPsetting", "LocalIPaddress": "$IP", "LocalPORT": "$PORT", "LocalAPSSID" : "$WiFiAPname"} +EOF + + +} + + +iptables_blockports () +{ +sudo iptables -A INPUT -p tcp --dport 5020 -j DROP +sudo iptables -A INPUT -p tcp --dport 5022 -j DROP + +sudo iptables-save > /home/pi/iptables.rules + +} + + +# --- RUN the functions +killpython +input_UI +system_update_light +#system_update_UI +install_dependencies +enable_I2C +modify_RClocal +fn_hostapd +fn_dnsmasq +fn_dhcpcd +fn_ifnames +install_mjpegstr +install_squid3 +install_hydrosys4 # this should be called before the DHT22 , SPI and BMP due to local library references +install_DHT22lib +install_SPIlib +install_BMPlib +install_MotorShieldlib +edit_defaultnetworkdb +#edit_networkdb +iptables_blockports + +echo "installation is finished!!! " diff --git a/changelog/change b/changelog/change index 6e133f0..7af3851 100644 --- a/changelog/change +++ b/changelog/change @@ -233,7 +233,9 @@ Change the apscheduler interval including end_date. This will avoid accidental d add config with stepper motor +2018-12-15 -> release 91 +Start scheduler after internet connection to avoid sudden time readjustment diff --git a/networkmod.py b/networkmod.py index ccfbe38..8e2baa1 100644 --- a/networkmod.py +++ b/networkmod.py @@ -34,7 +34,7 @@ def wifilist_ssid(): # get all cells from the air ssids=[] - network = wpa_cli_mod.get_networks("wlan0") + network = wpa_cli_mod.get_networks("wlan0",2) for item in network: ssids.append(item["ssid"]) return ssids diff --git a/selectedplanmod.py b/selectedplanmod.py index 4b798d5..31efe0e 100644 --- a/selectedplanmod.py +++ b/selectedplanmod.py @@ -6,6 +6,7 @@ import logging import os import os.path +import threading import string from datetime import datetime,date,timedelta import time @@ -155,7 +156,7 @@ def startpump(target,activationseconds,MinAveragetemp,MaxAverageHumid): print 'Pump ON, optional time for sec =', duration actuatordbmod.insertdataintable(target,duration) - + return True def periodicdatarequest(sensorname): @@ -168,7 +169,8 @@ def periodicdatarequest(sensorname): automationmod.automationcheck(sensorname) # call to automatic algorithms for watering autowateringmod.autowateringcheck(sensorname) - + + return True def heartbeat(): @@ -260,7 +262,7 @@ def heartbeat(): print "No next run for master scheduler" logger.warning('Heartbeat check , Master Scheduler Interrupted') emailmod.sendallmail("alert","Master Scheduler has been interrupted, try to restart scheduler") - setmastercallback() + resetmastercallback() # check if there have been errors in Syslog if DEBUGMODE: @@ -286,15 +288,17 @@ def sendmail(target): if issent: actuatordbmod.insertdataintable(target,1) print "Action", target , " " , datetime.now() - + + return True def takephoto(target): logger.info('take picture %s', datetime.now().strftime("%Y-%m-%d %H:%M:%S")) hardwaremod.takephoto() # save action in database actuatordbmod.insertdataintable(target,1) - print "Action", target ," " , datetime.now() - + print "Action", target ," " , datetime.now() + return True + def setlight(MinimumLightinde,MaximumLightONinde): # removed because obsolete return True @@ -314,8 +318,8 @@ def setlight(MinimumLightinde,MaximumLightONinde): def setmastercallback(): logger.info('Master Scheduler - Setup daily jobs') #set daily call for mastercallback at midnight - starttime=datetime(datetime.now().year, datetime.now().month, datetime.now().day, 0, 0, 0) - starttimeloc=starttime + timedelta(seconds=1) + thedateloc=datetime.now() + starttimeloc=thedateloc.replace(hour=23, minute=59, second=59) #convert to UTC time starttime=clockmod.convertLOCtoUTC_datetime(starttimeloc) print "setup master job" @@ -326,21 +330,49 @@ def setmastercallback(): print 'Date value for job scheduler not valid' logger.warning('Heartbeat check , Master Scheduler not Started properly') mastercallback() + + return True -#add_job(func, trigger=None, args=None, kwargs=None, id=None, name=None, misfire_grace_time=undefined, coalesce=undefined, max_instances=undefined, next_run_time=undefined, jobstore='default', executor='default', replace_existing=False, **trigger_args) +def waitandsetmastercallback(pulsesecond, offset): + + try: + f=float(pulsesecond) + secondint=int(f)+offset + except: + secondint=200 + print "try to setmastercallback after " , secondint , " seconds" + t = threading.Timer(secondint, setmastercallback ).start() + +def resetmastercallback(): + logger.info('Reset Master Scheduler') + # remove all the current jobs + print "selected new table" + SchedulerMod.removealljobs() + print "are still jobs there" + SchedulerMod.sched.print_jobs() + setmastercallback() + print "new jobs there" + SchedulerMod.sched.print_jobs() + return True + def mastercallback(): # clean old data of the database (pastdays) + logger.info('Remove data in exceed of one year') + pastdays=364 - sensordbmod.RemoveSensorDataPeriod(pastdays) - actuatordbmod.RemoveActuatorDataPeriod(pastdays) - hardwaremod.removephotodataperiod(364) - + #sensordbmod.RemoveSensorDataPeriod(pastdays) + logger.info('Sensor Remove data in exceed of one year') + #actuatordbmod.RemoveActuatorDataPeriod(pastdays) + logger.info('Actuator Remove data in exceed of one year') + #hardwaremod.removephotodataperiod(364) + logger.info('Photo Remove data in exceed of one year') + logger.info('Start other scheduler activities') # remove all jobs except masterscheduler #for job in SchedulerMod.sched.get_jobs(): @@ -365,7 +397,7 @@ def mastercallback(): setschedulercallback(calltype,timelist,argument,callback,callback) - + logger.info('Start other scheduler activities - sensor') # info file dedicate call-back --------------------------------------------- (sensor) @@ -385,6 +417,8 @@ def mastercallback(): setschedulercallback(calltype,timelist,argument,callback,hwname) timeshift=timeshift+shiftstep + logger.info('Start other scheduler activities - photo') + #<------> # info file dedicate quinto call-back ----------------------------------(takephoto) usedfor="photocontrol" @@ -397,6 +431,7 @@ def mastercallback(): argument.append(hwname) setschedulercallback(calltype,timelist,argument,callback,hwname) + logger.info('Start other scheduler activities - mail') # info ne file dedicate quarto call-back ---------------------------------------(sendmail) @@ -417,6 +452,8 @@ def mastercallback(): # empty #<----> + logger.info('Start other scheduler activities - pump') + # info file dedicate call-back ------------------------------------------------ (waterpump) @@ -470,7 +507,7 @@ def mastercallback(): setschedulercallback(calltype,timelist,argument,callback,pumpname) - + logger.info('Start other scheduler activities - doser') # info file dedicate call-back ------------------------------------------------ (pulsenutrient) @@ -507,7 +544,9 @@ def mastercallback(): argument.append(fertilizerpulsesecond) if (fertilizerpulsesecond)>0: #check if the duration in second is >0 setschedulercallback(calltype,timelist,argument,callback,dosername) - + + logger.info('Start other scheduler activities - finish') + return True def setschedulercallback(calltype,timelist,argument,callbackname,jobname): # jobname is used as unique identifier of the job @@ -559,9 +598,11 @@ def setschedulercallback(calltype,timelist,argument,callbackname,jobname): def start_scheduler(): SchedulerMod.start_scheduler() - + return True + def stop_scheduler(): - SchedulerMod.stop_scheduler() + SchedulerMod.stop_scheduler() + return True def readselectedmaininfo(maininfo): @@ -570,17 +611,10 @@ def readselectedmaininfo(maininfo): maininfo.append("Status") return True -def startnewselectionplan(): - print "selected new table" - SchedulerMod.removealljobs() - print "are still jobs there" - SchedulerMod.sched.print_jobs() - setmastercallback() - print "new jobs there" - SchedulerMod.sched.print_jobs() def removeallscheduledjobs(): - SchedulerMod.removealljobs() + SchedulerMod.removealljobs() + return True #--end --------//////////////////////////////////////////////////////////////////////////////////// diff --git a/sensordbmod.py b/sensordbmod.py index cc6f95f..a4a8bfa 100644 --- a/sensordbmod.py +++ b/sensordbmod.py @@ -138,7 +138,6 @@ def readallsensorsdatabase(): for value in databasevalues: sensorvalues[sensorname]=value[1] sensortimestamp[sensorname]=value[0] - print sensorvalues[sensorname] , sensortimestamp[sensorname] return sensorvalues def getSensorDataPeriod(selsensor,sensordata,enddate,pastdays): diff --git a/start.py b/start.py index 167cd3b..16b2c96 100644 --- a/start.py +++ b/start.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -Release="0.90" +Release="0.91" #--------------------- from loggerconfig import LOG_SETTINGS @@ -99,7 +99,15 @@ # finish logging init - +def runallconsistencycheck(): + wateringdbmod.consitencycheck() + autowateringdbmod.consistencycheck() + automationdbmod.consistencycheck() + fertilizerdbmod.consitencycheck() + autofertilizerdbmod.consistencycheck() + sensordbmod.consistencycheck() + actuatordbmod.consistencycheck() + return True @@ -121,14 +129,8 @@ print "path ",hardwaremod.get_path() MYPATH=hardwaremod.get_path() -wateringdbmod.consitencycheck() -autowateringdbmod.consistencycheck() -automationdbmod.consistencycheck() -fertilizerdbmod.consitencycheck() -autofertilizerdbmod.consistencycheck() -#scheduler setup--------------------- -selectedplanmod.start_scheduler() -selectedplanmod.setmastercallback() +# RUN ALL consistency chacks ------------------------ +runallconsistencycheck() #setup network connecton -------------------- try: @@ -137,6 +139,11 @@ except: print "No WiFi available" +#scheduler setup--------------------- +selectedplanmod.start_scheduler() +selectedplanmod.waitandsetmastercallback(networkmod.WAITTOCONNECT, 40) # plus 40 seconds respect to internet connection + + #prove varie qui --------------------------------------------------- #selectedplanmod.startpump("1","10","25","10") #selectedplanmod.setlight("","") @@ -830,7 +837,12 @@ def downloadit(): if not session.get('logged_in'): ret_data = {"answer":"Login Needed"} return jsonify(ret_data) - # send command to the actuator for test + # check the download destination folder exist otherwise create it + folderpath=os.path.join(MYPATH, "static") + folderpath=os.path.join(folderpath, "download") + if not os.path.exists(folderpath): + os.makedirs(folderpath) + recdata=[] ret_data={} @@ -1118,7 +1130,7 @@ def show_Calibration(): #on the contrary of the name, this show the setting men wateringdbmod.consitencycheck() fertilizerdbmod.consitencycheck() #scheduler setup--------------------- - selectedplanmod.setmastercallback() + selectedplanmod.resetmastercallback() #initiate the GPIO OUT pins hardwaremod.initallGPIOoutput() @@ -1326,7 +1338,7 @@ def wateringplan(): table1=wateringdbmod.gettable(0) # watering schema table2=wateringdbmod.gettable(2) # watering schema #print "after",table - selectedplanmod.startnewselectionplan() + selectedplanmod.resetmastercallback() if actiontype == "advconfig": print "open advanced setting" @@ -1386,7 +1398,7 @@ def autowatering(): autowateringdbmod.replacerow(element,dicttemp) flash('Table as been saved') - #selectedplanmod.startnewselectionplan() + #selectedplanmod.resetmastercallback() if actiontype == "reset": @@ -1477,7 +1489,7 @@ def automation(): automationdbmod.replacerow(element,dicttemp) flash('Table as been saved') - #selectedplanmod.startnewselectionplan() + #selectedplanmod.resetmastercallback() if actiontype == "reset": @@ -1577,7 +1589,7 @@ def fertilizerplan(): table=fertilizerdbmod.gettable(1) table1=fertilizerdbmod.gettable(0) #print "after",table - selectedplanmod.startnewselectionplan() + selectedplanmod.resetmastercallback() #add proper formatting for the Autofertilizer @@ -1809,14 +1821,9 @@ def hardwaresetting(): #on the contrary of the name, this show the setting menu # apply changes to the system if isdone: hardwaremod.restoredefault() # copy default to normal file and reload HWdata - wateringdbmod.consitencycheck() - autowateringdbmod.consistencycheck() - fertilizerdbmod.consitencycheck() - autofertilizerdbmod.consistencycheck() - sensordbmod.consistencycheck() - actuatordbmod.consistencycheck() + runallconsistencycheck() #scheduler setup--------------------- - selectedplanmod.setmastercallback() + selectedplanmod.resetmastercallback() #initiate the GPIO OUT pins hardwaremod.initallGPIOoutput() @@ -1864,15 +1871,9 @@ def hardwaresettingedit(): #on the contrary of the name, this show the setting hardwaremod.IOdatafromtemp() # apply changes to the system - - wateringdbmod.consitencycheck() - autowateringdbmod.consistencycheck() - fertilizerdbmod.consitencycheck() - autofertilizerdbmod.consistencycheck() - sensordbmod.consistencycheck() - actuatordbmod.consistencycheck() + runallconsistencycheck() #scheduler setup--------------------- - selectedplanmod.setmastercallback() + selectedplanmod.resetmastercallback() #initiate the GPIO OUT pins hardwaremod.initallGPIOoutput() return redirect(url_for('hardwaresetting')) @@ -1958,7 +1959,7 @@ def hardwaresettingeditfield(): #on the contrary of the name, this show the set hardwaremod.IOdatafromtemp() # apply changes to the system - # basically instead of the consistencycheck procedure it should be simply the rename procedure -- to be improved + # basically instead of the consistencycheck procedure it should be simply the rename procedure -- Done autowateringdbmod.replacewordandsave(oldnames,newnames) wateringdbmod.replacewordandsave(oldnames,newnames) @@ -1968,7 +1969,7 @@ def hardwaresettingeditfield(): #on the contrary of the name, this show the set sensordbmod.consistencycheck() actuatordbmod.consistencycheck() #scheduler setup--------------------- - selectedplanmod.setmastercallback() + selectedplanmod.resetmastercallback() #initiate the GPIO OUT pins hardwaremod.initallGPIOoutput() return redirect(url_for('show_Calibration')) diff --git a/templates/showsensordata.html b/templates/showsensordata.html index 87e2e89..22fbff0 100644 --- a/templates/showsensordata.html +++ b/templates/showsensordata.html @@ -136,7 +136,7 @@ grid:gridvar, - gridPadding: {top:80, left:30, right:30, bottom:70}, + gridPadding: {top:110, left:30, right:30, bottom:70}, legend:{ @@ -248,7 +248,7 @@ - gridPadding: {top:60, left:30, right:15, bottom:70}, + gridPadding: {top:90, left:30, right:15, bottom:70}, legend:{ @@ -348,7 +348,7 @@ var options = { grid:gridvar, - gridPadding: {top:60, left:20, right:30, bottom:70}, + gridPadding: {top:90, left:20, right:30, bottom:70}, legend:{ @@ -546,7 +546,7 @@ grid:gridvar, - gridPadding: {top:80, left:30, right:30, bottom:70}, + gridPadding: {top:110, left:30, right:30, bottom:70}, legend:{ diff --git a/wpa_cli_mod.py b/wpa_cli_mod.py index cb942c7..7ff6754 100644 --- a/wpa_cli_mod.py +++ b/wpa_cli_mod.py @@ -58,10 +58,11 @@ def get_networks(iface, retry=1): Grab a list of wireless networks within range, and return a list of dicts describing them. """ while retry > 0: - if "OK" in run_program(['wpa_cli', '-i' + iface , 'scan']): + output=run_program(['wpa_cli', '-i' + iface , 'scan']) + time.sleep(0.2) + if ("OK" in output.upper()): time.sleep(1) networks=[] - lines = run_program(['wpa_cli', '-i' + iface , 'scan_result']).split("\n") if lines: for line in lines[1:-1]: