Databas

Den nya ljusstyrningen blir lite mer avancerad (hoppas jag) än den gamla och jag tänker ha en databas i botten. Jag vill kunna styra ljuset manuellt via en webbsida och då är det behändigt att låta skriptet som skickar ut styrsignalerna hämta sina instruktioner från en databas som styrsidan uppdaterar. Då krävs det lite mer saker som ska installeras:

sudo apt-get install mysql-server phpmyadmin python3-pip
sudo python -m pip install mysql-connector
sudo python -m pip install mysql-connector-python-rf

När installationerna är klara kör man

sudo mysql --user=root mysql

CREATE USER 'username'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON *.* TO 'username'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
exit

för att skapa ditt eget admin-konto i MySQL (byt ut username och password). Sedan kan man surfa till din_pajs_ip_adress/phpmyadmin för att hantera databasen. Jag börjar med att skapa en ny användare som heter aqua-light och anger att det ska skapas en databas med samma namn där man har fulla behörigheter.

I databasen skapar jag fyra tabeller:

  1. config
    ID av typ INT, autoincrement, primary index
    Name av typ VARCHAR(255)
    Value av typ VARCHAR(255)
  2. manual
    ID av typ INT, autoincrement, primary index
    R av typ INT
    G av typ INT
    B av typ INT
    I av typ INT
  3. automatic
    ID av typ INT, autoincrement, primary index
    Sec av typ INT
    R av typ INT
    G av typ INT
    B av typ INT
    I av typ INT
  4. basedata
    ID av typ INT, autoincrement, primary index
    H av typ INT
    M av typ INT
    S av typ INT
    R av typ INT
    G av typ INT
    B av typ INT
    I av typ INT

När jag ändå är inne i phpMyAdmin skapar jag en post i config med Name automatic och Value 0. Jag lägger även till en rad i manual med bara nollor.

Tanken är att värdet automatic i config-tabellen ska ange om ljusrampen ska köras i manuellt eller automatiskt läge. I manuellt läge läser den värdena för rött, grönt och blått samt ljusstyrkan från tabellen manual. I automatiskt läge slår den upp vilka värden som ska sättas beroende på hur många sekunder det har gått sedan midnatt. Tabellen manual kommer alltså att ha en rad och tabellen automatic kommer att ha 86400 rader. Med lite webbsidor är det tänkt att man ska kunna växla mellan manuellt och automatiskt läge samt fylla tabellen automatic beroende på hur man vill att ljuset ska växla under dagen. Tabellen basedata innehåller reglerna man har satt upp för det automatiska ljuset.

Share

Repetition av temperatur

Hur man mäter temperatur och hur jag använder det för att styra ett relä som slår av och på värmaren är beskrivet på andra ställen i bloggen men här kommer en sammanställning och uppdatering.

Jag aktiverade 1-wire i raspi-config under uppsättningen av min paj och har anslutit min DS18B20 enligt anvisningarna från Cambridge University. För att den ska hittas och användas behöver två rader läggas till i /etc/modules:

w1-gpio 
w1-therm

För att kunna presentera data och statistik installerade jag webbservern Apache tillsammans med MRTG som kan presentera historiken grafiskt:

sudo apt-get install apache2 mrtg

För att MRTG ska få data från temperatur-sensorn krävs det en liten fil som jag kallar mrtg.py. Man får byta adressen till filen w1_slave till aktuell adress, varje sensor har sin egen:

#!/usr/bin/python
from time import strftime

tfile = open("/sys/bus/w1/devices/28-011553897dff/w1_slave", 'r')
text = tfile.read()
tfile.close()

secondline = text.split("\n")[1]
temperaturedata = secondline.split(" ")[9]
temperature = float(temperaturedata[2:])
temperature = int(temperature / 10)

print(str(temperature))
print("0")
print(strftime("%Y-%m-%d %H:%M:%S"))
print("Temperatur i kar 3")

Man behöver även byta ut /etc/mrtg.cfg mot en som hämtar data på rätt ställe och visar det som man vill:

#Mouter Traffic Grapher -- Sample Configuration File
######################################################################
# This file is for use with mrtg-2.5.4c

# Global configuration
WorkDir: /var/www/html/mrtg
WriteExpires: Yes
RunAsDaemon: Yes
Interval: 5

Title[^]: Temperaturstatistik for 

Title[kar3]: kar 3
PageTop[kar3]: <h1>Temperaturen i kar 3</h1>
Target[kar3]: `/usr/local/bin/aquacontrol/mrtg.py`
MaxBytes[kar3]: 4000
Options[kar3]: growright,gauge,expscale
Factor[kar3]: 0.01
YLegend[kar3]: Temperatur
YTicsFactor[kar3]: 0.01
ShortLegend[kar3]: C
Legend1[kar3]: Temperatur i grader celcius
Legend2[kar3]: 
Legend3[kar3]: Maximal 5 Minute Incoming Traffic
Legend4[kar3]: Maximal 5 Minute Outgoing Traffic
LegendI[kar3]:  Temp:
LegendO[kar3]: 

För att MRTG ska starta automatiskt behövs ett startscript, skapa filen mrtg i  /etc/init.d med följande innehåll:

N INIT INFO
# Provides:          mrtg
# Required-Start:    
# Required-Stop:     
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: mrtg init script
# Description:       This file is used to start, stop, restart, 
#					 and determined status of the mrtg daemon.
# Author: 			 iceflatline <iceflatline@gmail.com>
### END INIT INFO
 
### START OF SCRIPT
set -e
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="mrtg"
NAME=mrtg
DAEMON=/usr/bin/$NAME
DAEMON_ARGS="/etc/mrtg.cfg"
PIDFILE=/etc/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
 
# Exit if the mrtg package is not installed
[ -x "$DAEMON" ] || exit 0
 
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
 
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
 
# Function that starts the mrtg daemon
start()
{
	env LANG=C start-stop-daemon --start --quiet \
	--exec $DAEMON -- $DAEMON_ARGS
}
 
# Function that stops the mrtg daemon
stop()
{
	start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 \
	--pidfile $PIDFILE 
}
 
case "$1" in
  start)
	log_daemon_msg "Starting $DESC" 
	start
	case "$?" in
		0) log_end_msg 0 ;;
		1) log_end_msg 1 ;;
	esac
	;;
  stop)
	log_daemon_msg "Stopping $DESC"
	stop
	case "$?" in
		0) log_end_msg 0 ;;
		1) log_end_msg 1 ;;
	esac
	;;
  restart|force-reload)
	log_daemon_msg "Restarting $DESC" 
	stop
	case "$?" in
	  0|1)
		start
		case "$?" in
			0) log_end_msg 0 ;;
			1) log_end_msg 1 ;; 
		esac
		;;
	esac
	;;
	status)
    status_of_proc "$DAEMON" "$NAME"  
    ;;
  *)
	echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" 
	;;
esac
exit 0
### END OF SCRIPT

Kör sedan

sudo chmod +x /usr/local/bin/aquacontrol/mrtg.py 
sudo chmod +x /etc/init.d/mrtg 
sudo systemctl daemon-reload 
sudo update-rc.d mrtg defaults

så ska MRTG-biten vara klar. Dags för lite styrning! Följande Python-skript läser av temperaturen varje minut, kollar mot gränsvärden, slår av och på värmaren och larmar via epost om det avviker för mycket. Ange dina egna epostuppgifter och förstås rätt adress till w1_slave-filen som vanligt.

#!/usr/bin/python
import RPi.GPIO as GPIO
import time
import datetime
import syslog
import smtplib
from time import strftime

syslog.openlog('aqua-temp')
syslog.syslog('Aqua-temp started')

# Definiera temperaturgranser
alarmLow = 24
alarmHigh = 27
tempLow = 24.9
tempHigh = 25.1

# Klasser
		
# Variabler
heatOn = 0
heatOff = 1
heater = 22
tempLarm = False
heatStatus = False

# Funktioner
def sendMail(subject, msg):
	fromaddr = 'me self <me@self.com>'
	toaddr  = 'me self <me@self.com>'
	message = ('From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n%s' % (fromaddr, toaddr, subject, msg))
	username = 'username'
	password = 'password'

	server = smtplib.SMTP('smtp.gmail.com:587')
	server.starttls()
	server.login(username,password)
	server.sendmail(fromaddr, toaddr, message)
	server.quit()
	syslog.syslog('Mail sent')

def writeTemp(temp):
	tfile = open('/var/www/html/temp.html', 'w')
	tfile.write('<html><head>')
	tfile.write('<title>Info för kar 3</title>')
	tfile.write('<META HTTP-EQUIV="refresh" CONTENT="60">')
	tfile.write('</head><body>')
	tfile.write(strftime("%Y-%m-%d %H:%M:%S"))
	tfile.write('<h1>Temperaturen i kar 3 är '+str(temp)+'°C</h1>')
	tfile.write('<h2>Värmaren är ')
	if heatStatus: tfile.write('på</h2>') 
	else: tfile.write('av</h2>')
	tfile.write('<p><a href="/mrtg/kar3.html">Historik</a>')
	tfile.write('</body></html>')
	tfile.close()
	
def checkTemp():
	global tempLarm
	global heatStatus
	
	tfile = open("/sys/bus/w1/devices/28-011553897dff/w1_slave", 'r')
	text = tfile.read()
	tfile.close()

	secondline = text.split("\n")[1]
	temperaturedata = secondline.split(" ")[9]
	temperature = float(temperaturedata[2:])
	temperature = float(int((temperature/100)+0.5))/10

	if (temperature < alarmLow or temperature > alarmHigh):
		if not tempLarm:
			syslog.syslog('Temp is wrong')
			sendMail("Temperaturen ar felaktig", "Temperaturen i kar 3 ar nu "+str(temperature))
			tempLarm = True
	else:
		if tempLarm:
			syslog.syslog('Temp is normal again')
			sendMail("Temperaturen ar normal", "Temperaturen i kar 3 ar nu "+str(temperature))
			tempLarm = False

	if (temperature <= tempLow):
		if not heatStatus:
			syslog.syslog('Temp is '+str(temperature)+'. Heater switched on')
			GPIO.output(heater, heatOn)
			heatStatus = True
	if (temperature >= tempHigh):
		if heatStatus:
			syslog.syslog('Temp is '+str(temperature)+'. Heater switched off')
			GPIO.output(heater, heatOff)
			heatStatus = False
	
	writeTemp(temperature)
	
# Initiera GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(heater, GPIO.OUT)
GPIO.output(heater, heatOff)
syslog.syslog('GPIO initialized, heater switched off')

# Huvudloop
while True:
	checkTemp()
	time.sleep(60)

För att skriptet ska starta automatiskt behöver man skapa filen aqua-temp.service i /lib/systemd/system med följande innehåll:

[Unit]
Description=Aqua-Temp
After=multi-user.target

[Service]
Type=idle
ExecStart=/usr/local/bin/aquacontrol/aqua-temp.py

[Install]
WantedBy=multi-user.target

Kör sedan

sudo chmod +x /usr/local/bin/aquacontrol/aqua-temp.py 
sudo chmod 644 /lib/systemd/system/aqua-temp.service 
sudo systemctl daemon-reload 
sudo systemctl enable aqua-temp.service

så ska det starta automatiskt vid omstart. Det är praktiskt att få loggen som skapas till en egen fil. Skapa filen /etc/rsyslog.d/aqua-temp.conf med innehållet

if $programname == 'aqua-temp' then /var/log/aqua-temp.log

Överkurs

Ibland kan det vara fiffigt att kunna hämta ut data i JSON-format. Jag har därför följande lilla fil, vid namn temp-xml.py, placerad i /var/www/cgi-bin. Ja, du behöver justera sökvägen till w1_slave…

#!/usr/bin/python

tfile = open("/sys/bus/w1/devices/28-011553897dff/w1_slave", 'r')
text = tfile.read()
tfile.close()

secondline = text.split("\n")[1]
temperaturedata = secondline.split(" ")[9]
temperature = float(temperaturedata[2:])
temperature = float(int((temperature/100)+0.5))/10

print ("Content-type: text/html\n")
print ('<?xml version="1.0" encoding="UTF-8"?>')
print ('<rss version="2.0">')
print ('  <item>')
print ('    <temp3>'+str(temperature)+'</temp3>')
print ('  </item>')
print ('</rss>')

För att Apache ska gå med på att köra python-script, och begripa vad cgi-bin är, behöver dessa rader läggas till i /etc/apache2/sites-available/000-default.conf efter DocumentRoot-raden

        ScriptAlias /cgi-bin/ /var/www/cgi-bin/
        <Directory "/var/www/cgi-bin">
                AllowOverride None
                Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
                Order allow,deny
                Allow from all
        </Directory>

Kör sedan

sudo chmod +x /var/www/cgi-bin/temp-xml.py 
sudo a2enmod cgi 
sudo service apache2 restart

så ska det hela rulla.

Share

Python 3

I Raspbian Stretch installeras både Python 2 och Python 3 men Python 2 är default. Jag vill köra trean som standard vilket kräver lite pill.

sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.5 2

Verifiera att rätt version används med

python --version

Om det inte är trean som körs kan man tvinga vilken version man vill använda med

sudo update-alternatives --config python

Allt är inte förinstallerat för python3 så man får lägga till lite.

sudo apt-get install python3-rpi.gpio
Share

Nattlig omstart

Om man programmerar så dåligt som jag gör blir det lätt minnesläckor och annat som med tiden får pajen att stanna. Jag brukar lösa det genom att schemalägga en nattlig omstart. Kör

sudo crontab -e

och lägg in

0 4 * * * /sbin/shutdown -r now

sist så startar den om klockan fyra varje natt.

Share

LED-ramp TNG

För den icke sci-fi-bevandrade står TNG för The Next Generation och det är precis det jag dragit igång. Vi stuvar om lite bland karen hemma och kastar in ett nytt 540-liters vilket kräver nya ramper och ny teknik. Jag behåller Raspberry Pi som styrning men istället för reläkontrollerade lysdioder använder jag adresserbara LED-strips. Ett par beställningar är gjorda på eBay och i väntan på leverans kan man sätta upp den Raspberry Pi som ska styra det hela.

Raspbian Stretch Lite är hemtaget och skrivet till SD-kortet med hjälp av Etcher. Om man monterar SD-kortet igen på datorn efter att ha skrivit till det kommer man åt en partition som heter boot. Där kan man skapa en tom fil som heter ssh (ska fungera med ssh.txt också men det är oprövat) och en fil som heter wpa_supplicant.conf med följande innehåll:

country=SE
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
 
network={
ssid="your_real_wifi_ssid"
scan_ssid=1
psk="your_real_password"
key_mgmt=WPA-PSK
}

Du får förstås skriva in dina egna SSID och PSK-uppgifter men sedan är det bara att sätta SD-kortet i pajen, slå på strömmen och logga in via SSH. Inget behov av tangentbord och skärm med andra ord! Filerna som man skapade gör att SSH är aktiverat och att den automatiskt ansluter till WiFi.

Som vanligt börjar jag med att köra

sudo raspi-config

för att ställa in diverse parametrar. Eftersom jag planerar att köra min vanliga temperaturstyrning slår jag bland annat på 1-wire under Interfacing options. Filsystemet utökas som vanligt under Advanced options och sedan är det dags för en omstart innan jag uppdaterar systemet med

sudo apt-get update 
sudo apt-get upgrade

Sedan är det bara resten kvar!

Share

Liten uppdatering

Det har gått ett halvår sedan förra uppdateringen och vi har inte bara hunnit med Örebros vårauktion utan även årets höstauktion. Lite annat har kommit emellan så full styrning på ljuset är inte klart än utan allt slås av och på via Switchking som så mycket annat ljus här hemma. Annars är allt på plats med rör och invånare i karen.

Share