commit 11f7d440ff3370f635eaf60e615f54a58ce108be Author: Souti Date: Thu Mar 6 11:09:58 2025 +0100 first commit diff --git a/AcerManon.sh b/AcerManon.sh new file mode 100755 index 0000000..db35000 --- /dev/null +++ b/AcerManon.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +lockfile-create "/tmp/AcerManon.lockfile" +/usr/bin/rsync -arvlp --bwlimit=1000 --size-only --exclude videos --exclude AppData --exclude Downloads --exclude Music /media/Acer/admin/ /media/MEMUP/AcerManon/ >/tmp/sync.log 2>/tmp/sync.err +lockfile-remove "/tmp/AcerManon.lockfile" diff --git a/AkhesaSouti.sh b/AkhesaSouti.sh new file mode 100755 index 0000000..6ec45bd --- /dev/null +++ b/AkhesaSouti.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +lockfile-create "/tmp/AkhesaSouti.lockfile" +/usr/bin/rsync -arvlp --bwlimit=1000 --size-only --exclude videos --exclude AppData --exclude Downloads --exclude Music /media/Akhesa/Souti/ /media/MEMUP/AkhesaSouti/ >/tmp/sync.log 2>/tmp/sync.err +lockfile-remove "/tmp/AkhesaSouti.lockfile" diff --git a/AkhesaTheo.sh b/AkhesaTheo.sh new file mode 100755 index 0000000..e0980a1 --- /dev/null +++ b/AkhesaTheo.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +lockfile-create "/tmp/AkhesaTheo.lockfile" +/usr/bin/rsync -arvlp --bwlimit=1000 --size-only --exclude videos --exclude AppData --exclude Downloads --exclude Music /media/Akhesa/Théo/ /media/MEMUP/AkhesaTheo/ >/tmp/sync.log 2>/tmp/sync.err +lockfile-remove "/tmp/AkhesaTheo.lockfile" diff --git a/Blender/sheepit-client-6.2020.0.jar b/Blender/sheepit-client-6.2020.0.jar new file mode 100644 index 0000000..95ab366 Binary files /dev/null and b/Blender/sheepit-client-6.2020.0.jar differ diff --git a/Hackintosh.sh b/Hackintosh.sh new file mode 100755 index 0000000..e1c517d --- /dev/null +++ b/Hackintosh.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +lockfile-create "/tmp/Hackintosh.lockfile" +if [ $( mount | grep Hackintosh | wc -l ) == 0 ] ; +then +sshfs souti@192.168.1.26:/Volumes/Data/ /media/Hackintosh/ +fi + +if [ $( mount | grep Hackintosh | wc -l ) == 1 ] ; +then + rsync -rvl --size-only /media/WDBlue/Musique/ /media/Hackintosh/Musique/ + rsync -rvl --size-only /media/WDBlue/SeriesTV/ /media/Hackintosh/SeriesTV/ + #rsync -rvl --progress --size-only /media/WDBlue/StockagePhoto/ /media/Hackintosh/StockagePhoto/ + rsync -rvl --size-only /media/WDBlue/films/ /media/Hackintosh/films/ +fi + +# /usr/bin/rsync -arvlp --bwlimit=1000 --size-only --exclude videos --exclude AppData --exclude Downloads --exclude Music /media/Acer/admin/ /media/MEMUP/AcerManon/ >/tmp/sync.log 2>/tmp/sync.err +lockfile-remove "/tmp/Hackintosh.lockfile" diff --git a/JSON_POUR_UNDERGROUND.sh b/JSON_POUR_UNDERGROUND.sh new file mode 100644 index 0000000..cb405f9 --- /dev/null +++ b/JSON_POUR_UNDERGROUND.sh @@ -0,0 +1,2 @@ +wget -O - http://api.wunderground.com/api/48a08328a93a18a1/conditions/q/pws:ISAINTGR13.json + diff --git a/Musique.sh b/Musique.sh new file mode 100644 index 0000000..a41a641 --- /dev/null +++ b/Musique.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +mount -t cifs //musique.home/sdcard/Musique /mnt/Musique -o username=souti,password=setaou,rw,uid=$(id -u),gid=$(id -g) + +for dir in mp3 flac Classique Clips Concerts "Chansons Francaises"; do + rsync -aprvhu --size-only --delete "/media/WDBlue/Musique/$dir" /mnt/Musique +done diff --git a/MySerial.py b/MySerial.py new file mode 100644 index 0000000..67ba954 --- /dev/null +++ b/MySerial.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python + +import serial +import string +import re # Matches +import os + +test=serial.Serial("/dev/ttyACM0",9600) +test.open() +onSort = False +try: + while not onSort: + line = test.readline() + sp = line.split(' ') + result = bool('fumee' in line) + if result: + print(line) + print(sp[0]) + print(sp[1]) + print(sp[2]) + #print(line[6:9]) + #print(line[14:18]) + #print(line[24:26]) + spCo = sp[0].split('=') + spButane = sp[1].split('=') + spPhoto = sp[2].split('=')[1].split('\r') + #print(spPhoto[1].split('\r')) + os.system("curl \"http://localhost:81/json.htm?type=command¶m=udevice&idx=110&nvalue=" + spCo[1] + "\"") + os.system("curl \"http://localhost:81/json.htm?type=command¶m=udevice&idx=109&nvalue=" + spButane[1] + "\"") + os.system("curl \"http://localhost:81/json.htm?type=command¶m=udevice&idx=107&svalue=" + spPhoto[0] + "\"") + onSort = True + +except KeyboardInterrupt: + pass # do cleanup here + +test.close() + diff --git a/PhilaeHome.sh b/PhilaeHome.sh new file mode 100755 index 0000000..07d715c --- /dev/null +++ b/PhilaeHome.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +lockfile-create "/tmp/PhilaeHome.lockfile" +/usr/bin/rsync -arvlp --bwlimit=1000 --size-only --delete-during --exclude Téléchargements --exclude videos --exclude .arduino15 --exclude Downloads --exclude Music /media/WDBlue/PhilaeHome/* /home/souti/ >/tmp/sync.log 2>/tmp/sync.err +lockfile-remove "/tmp/PhilaeHome.lockfile" diff --git a/Surveillance.sh b/Surveillance.sh new file mode 100755 index 0000000..dbd13bc --- /dev/null +++ b/Surveillance.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +WATCH_DIRS=("mp3" "flac" "Classique" "Clips" "Concerts" "Chansons Francaises") # Répertoire à surveiller +#SCRIPT="/opt/domoticz/scripts/Musique.sh" # Script à exécuter + +mount -t cifs //musique.home/sdcard/Musique /mnt/Musique -o username=souti,password=setaou,rw,uid=$(id -u),gid=$(id -g) + + +for dir in "${WATCH_DIRS[@]}"; do + inotifywait -m -e create,modify,delete,move "/media/WDBlue/Musique/$dir" | + while read -r directory events filename; do + echo "Changement détecté dans $directory : $events sur $filename" + #bash "$SCRIPT" "$directory" "$filename" "$events" + lockfile-create "/tmp/synchro.lockfile" + rsync -aprvhu --size-only "$directory/" "/mnt/Musique/$dir/" > "/tmp/synch_directory" + lockfile-remove "/tmp/synchro.lockfile" + done & +done + diff --git a/_domoticz_main b/_domoticz_main new file mode 100644 index 0000000..bf57c38 --- /dev/null +++ b/_domoticz_main @@ -0,0 +1,10 @@ +#!/bin/sh + +startup_path=$1 +hardware_id=$2 +device_id=$3 +status=$4 +status2=$5 +devname=$6 + +echo "startup_path=${startup_path}, hardware_id=${hardware_id}, device_id=${device_id}, status=${status}, status2=${status2}, devname=${devname}" diff --git a/_domoticz_main.bat b/_domoticz_main.bat new file mode 100644 index 0000000..6191d5e --- /dev/null +++ b/_domoticz_main.bat @@ -0,0 +1,10 @@ +@echo off +set startup_path=%1 +set hardware_id=%2 +set device_id=%3 +set status=%4 +set status2=%5 +set devname=%6 + +:: %startup_path% %hardware_id% %device_id% %status% %status2% %devname% + diff --git a/backup/domoticz b/backup/domoticz new file mode 100755 index 0000000..d29a076 --- /dev/null +++ b/backup/domoticz @@ -0,0 +1,17 @@ +#!/bin/bash + +service domoticz.sh stop + +cd /opt/domoticz/ +#tar -czf /tmp/domoticz.tgz . +tar --exclude="./backups" -czf /tmp/domoticz.tgz . +#tar -cz --exclude="./backups" -f /tmp/domoticz.tgz . + +cp /tmp/domoticz.tgz /media/WDBlue/backup/ImagesMyPi/domoticz"$(date '+%Y-%m-%d')".tgz +#scp /tmp/domoticz.tgz pi@volumio2:/media/WDRed/backup/ + +service domoticz.sh start + +#rm /tmp/domoticz.tgz + + diff --git a/backup/domoticzOpt b/backup/domoticzOpt new file mode 100755 index 0000000..a594296 --- /dev/null +++ b/backup/domoticzOpt @@ -0,0 +1,8 @@ +#!/bin/bash + +cd /opt/domoticz; +/bin/tar cvzf /tmp/opt.tgz *; +/bin/cp /tmp/opt.tgz /media/Backup/domoticz/domoticz"$(date '+%Y-%m-%d')".tgz; + + + diff --git a/backup/domoticzScripts b/backup/domoticzScripts new file mode 100755 index 0000000..cc4ee06 --- /dev/null +++ b/backup/domoticzScripts @@ -0,0 +1,7 @@ +#!/bin/bash + +cd /opt/domoticz/scripts/; +/bin/tar cvzf /tmp/scriptsDomoticz.tgz *; +/bin/cp /tmp/scriptsDomoticz.tgz /media/Backup/domoticz/scriptsDomoticz"$(date '+%Y-%m-%d')".tgz; + + diff --git a/backup/domoticzWww b/backup/domoticzWww new file mode 100755 index 0000000..0a070e9 --- /dev/null +++ b/backup/domoticzWww @@ -0,0 +1,7 @@ +#!/bin/bash + +cd /var/www/; +/bin/tar cvzf /tmp/varwww.tgz *; +/bin/cp /tmp/varwww.tgz /media/Backup/domoticz/varwww"$(date '+%Y-%m-%d')".tgz; + + diff --git a/backup/exclude.txt b/backup/exclude.txt new file mode 100644 index 0000000..05badca --- /dev/null +++ b/backup/exclude.txt @@ -0,0 +1,2 @@ +domoticz +domoticz*.db* diff --git a/backup/octoprint b/backup/octoprint new file mode 100755 index 0000000..9ca7f63 --- /dev/null +++ b/backup/octoprint @@ -0,0 +1,7 @@ +#!/bin/bash + +tar czf /tmp/octoprint.tgz /opt/OctoPrint/* + +cp /tmp/octoprint.tgz /media/WDBlue/backup/ImagesMyPi/octoprint"$(date '+%Y-%m-%d')".tgz + +tar cvzf /media/WDBlue/backup/ImageMyPi/klipper_configurated"$(date '+%Y-%m-%d')".tgz /home/souti/klipper /home/souti/klippy-env /home/souti/printer.cfg diff --git a/backup/saveOctoprint.sh b/backup/saveOctoprint.sh new file mode 100755 index 0000000..aab4536 --- /dev/null +++ b/backup/saveOctoprint.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +/bin/tar -cvzf /media/WDBlue/backup/ImagesMyPi/Octoprint"$(date '+%Y-%m-%d')".tgz /home/souti/OctoPrint/* +/bin/tar -cvzf /media/WDBlue/backup/ImagesMyPi/saveOctoprintData"$(date '+%Y-%m-%d')".tgz --exclude=uploads --exclude=logs /home/souti/.octoprint/ +/bin/tar -cvzf /media/WDBlue/backup/ImagesMyPi/saveOctoprint2Data"$(date '+%Y-%m-%d')".tgz --exclude=uploads --exclude=logs /home/souti/.octoprint2/ diff --git a/backupOctprint.sh b/backupOctprint.sh new file mode 100644 index 0000000..c890a9a --- /dev/null +++ b/backupOctprint.sh @@ -0,0 +1,3 @@ +!/bin/bash + +tar cvz --exclude=uploads --exclude=logs -f /media/WDBlue/backup/saveOctoprint"$(date '+%H')".tgz /home/souti/.octoprint/ diff --git a/banned.sh b/banned.sh new file mode 100755 index 0000000..dc3b230 --- /dev/null +++ b/banned.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +#var=`/usr/bin/fail2ban-client status sshd |grep "Total banned"|awk -F":" '{print $2}'` + +# remove leading whitespace characters +#banned="${var#"${var%%[![:space:]]*}"}" + +banned=`/usr/sbin/iptables -L -n --line|/bin/grep REJECT|wc -l` +json="http://localhost:81/json.htm?type=command¶m=udevice&idx=700&svalue=$banned" +echo $json + +curl -s -i -H "Accept: application/json" $json +echo $banned; diff --git a/batterie.py b/batterie.py new file mode 100644 index 0000000..0089a72 --- /dev/null +++ b/batterie.py @@ -0,0 +1,43 @@ +import curses +import json +import requests + +# URL de l'API +url = "http://192.168.1.18/getData" + +def fetch_data(url): + response = requests.get(url) + if response.status_code == 200: + return response.json() + else: + return {} + +def display_data(screen, data): + screen.clear() + + rows, cols = screen.getmaxyx() + + # Clés et valeurs + keys = list(data.keys()) + values = list(data.values()) + + # Largeur des colonnes + col_width = max(len(key) for key in keys) + 2 # Largeur de la colonne des clés + col_width_value = max(len(str(value)) for value in values) + 2 # Largeur de la colonne des valeurs + + for idx, (key, value) in enumerate(data.items()): + key_str = f"{key}:" + value_str = str(value) + screen.addstr(idx, 0, key_str.ljust(col_width)) + screen.addstr(idx, col_width, value_str.ljust(col_width_value)) + + screen.refresh() + +def main(screen): + data = fetch_data(url) + display_data(screen, data) + screen.getch() + +if __name__ == "__main__": + curses.wrapper(main) + diff --git a/batterie2.py b/batterie2.py new file mode 100644 index 0000000..3958998 --- /dev/null +++ b/batterie2.py @@ -0,0 +1,74 @@ +import curses +import json +import requests +import time + +# URL de l'API +url = "http://192.168.1.59/getData" +excluded_keys = {"FW", "PID", "SER#", "TENSIONS", "OR", "HSDS", "XY_ON", "XY_AV", "XY_AC", "XY_AW", "CONS"} + +def fetch_data(url): + response = requests.get(url) + if response.status_code == 200: + return response.json() + else: + return {} + +def display_headers(screen, keys, max_width): + screen.clear() + for idx, key in enumerate(keys): + if idx * max_width < curses.COLS: + try: + screen.addstr(0, idx * max_width, key.ljust(max_width)[:max_width], curses.color_pair(1)) + except curses.error: + pass + screen.refresh() + +def display_data(screen, data, keys, line, max_width): + for idx, key in enumerate(keys): + if idx * max_width < curses.COLS: + value_str = str(data.get(key, "")) + if key == "PPV" and float(value_str) > 0: + color = curses.color_pair(3) # Red background for PPV > 0 + else: + color = curses.color_pair(2) # Default color + screen.addstr(line, idx * max_width, value_str.ljust(max_width)[:max_width], color) + + screen.refresh() + +def main(screen): + curses.curs_set(0) # Hide the cursor + screen.nodelay(True) # Don't block waiting for user input + # Initialize colors + curses.start_color() + curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE) # Header color + curses.init_pair(2, curses.COLOR_BLACK, curses.COLOR_CYAN) # Data color + curses.init_pair(3, curses.COLOR_RED, curses.COLOR_CYAN) # PPV > 0 color + + keys = None + max_width = 9 # Maximum width for each column + + line = 1 + while True: + data = fetch_data(url) + if line == 1: #keys is None: + keys = [key for key in data.keys() if key not in excluded_keys] + display_headers(screen, keys, max_width) + + try: + display_data(screen, data, keys, line, max_width) + except curses.error: + line = 0 + screen.clear() + pass + + line += 1 + + time.sleep(5) + + if screen.getch() != -1: + break + +if __name__ == "__main__": + curses.wrapper(main) + diff --git a/buienradar_rain.pl b/buienradar_rain.pl new file mode 100644 index 0000000..b0c3629 --- /dev/null +++ b/buienradar_rain.pl @@ -0,0 +1,96 @@ +#!/usr/bin/perl -w + +use strict; +use LWP::UserAgent; +use HTTP::Cookies; + +my $lat=50.22041; +my $long=5.89744; +my $domoticz_ip="127.0.0.1"; +my $domoticz_port="8080"; +my $domoticz_sensor_idx="2442"; +my $duration=15; + +my @user_agents = ( + 'Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)' + ); + +my $ua = LWP::UserAgent->new( + #Set agent name, we are not a script! :) + agent => $user_agents[rand @user_agents], + cookie_jar => HTTP::Cookies->new(), + ); + +my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(); + +my $startTime=($hour*60)+$min; +my $endTime=$startTime+$duration; + +my $url = "http://gps.buienradar.nl/getrr.php?lat=$lat&lon=$long"; +my $response = $ua->get($url); + +unless ($response->is_success) { + # hmm, let's retry + $response = $ua->get($url); + + unless ($response->is_success) { + # still no luck; sleep and retry + sleep 1; + $response = $ua->get($url); + + unless ($response->is_success) { + print "Could not connect to buienradar.nl.\n"; + exit 0; + } + } +} + +my $data = $response->content; + +unless ($data =~ /\A((\d{3})?\|\d{2}:\d{2}\r?\n)+\z/) { + print "Could not parse the data returned by buienradar.nl.\n"; + exit 0; +} + +my $total_rain_predictions=0; +my $total_rain_values=0; + +while ($data =~ s/\A(\d{3})?\|(\d{2}:\d{2})\r?\n//) { + my ($value, $mtime) = ($1, $2); + + if (defined $value) { + + my @hour_min = split(':', $mtime); + my $mhour = $hour_min[0]; + my $mmin = $hour_min[1]; + my $calc_time=($mhour*60)+$mmin; + if (($calc_time>=$startTime)&&($calc_time<=$endTime)) { + $value =~ s/\A0+(\d)/$1/; + $total_rain_predictions+=$value; + $total_rain_values+=1; + } + } +} + +my $result = "0.0"; + +if ($total_rain_values!=0) { + my $rain_0_100=($total_rain_predictions/$total_rain_values)*0.392156862745098; + $result = sprintf("%.2f", $rain_0_100); +} + +$url = "http://$domoticz_ip:$domoticz_port/json.htm?type=command¶m=udevice&idx=$domoticz_sensor_idx&nvalue=0&svalue=$result"; +$response = $ua->get($url); + +unless ($response->is_success) { + print "Error sending data to domoticz!\n"; + exit 0; +} +$data = $response->content; + +if (index($data, "\"OK\"") == -1) { + print "Error sending data to domoticz!\n"; + exit 0; +} + +print "OK, precip=$result\n"; diff --git a/buienradar_rain_example.pl b/buienradar_rain_example.pl new file mode 100644 index 0000000..3743a8b --- /dev/null +++ b/buienradar_rain_example.pl @@ -0,0 +1,123 @@ +#!/usr/bin/perl -w + +=head1 buienradar_rain.pl + +Installation: + +Perl, you need to install the LWP module: +sudo apt-get install libjson-perl + +In Domoticz create a Dummy Percentage sensor. +Next go to the Devices overview, and write down the 'idx' value of the sensor. + +Copy this file to another location and edit the setting below to match your situation. + +cp /home/pi/domoticz/scripts/buienradar_rain_example.pl /home/pi/domoticz/buienradar_rain.pl +nano /home/pi/domoticz/buienradar_rain.pl + +Next add a Crontab rule: + +crontab -e + +Add the following line at the end: + +*/5 * * * * perl /home/pi/domoticz/buienradar_rain.pl + +In 5 minutes, the sensor should work + +=cut + +use strict; +use LWP::UserAgent; +use HTTP::Cookies; + +my $lat=50.22041; +my $long=5.89744; +my $domoticz_ip="127.0.0.1"; +my $domoticz_port="8080"; +my $domoticz_sensor_idx="2442"; +my $duration=15; + +my @user_agents = ( + 'Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)' + ); + +my $ua = LWP::UserAgent->new( + #Set agent name, we are not a script! :) + agent => $user_agents[rand @user_agents], + cookie_jar => HTTP::Cookies->new(), + ); + +my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(); + +my $startTime=($hour*60)+$min; +my $endTime=$startTime+$duration; + +my $url = "http://gps.buienradar.nl/getrr.php?lat=$lat&lon=$long"; +my $response = $ua->get($url); + +unless ($response->is_success) { + # hmm, let's retry + $response = $ua->get($url); + + unless ($response->is_success) { + # still no luck; sleep and retry + sleep 1; + $response = $ua->get($url); + + unless ($response->is_success) { + print "Could not connect to buienradar.nl.\n"; + exit 0; + } + } +} + +my $data = $response->content; + +unless ($data =~ /\A((\d{3})?\|\d{2}:\d{2}\r?\n)+\z/) { + print "Could not parse the data returned by buienradar.nl.\n"; + exit 0; +} + +my $total_rain_predictions=0; +my $total_rain_values=0; + +while ($data =~ s/\A(\d{3})?\|(\d{2}:\d{2})\r?\n//) { + my ($value, $mtime) = ($1, $2); + + if (defined $value) { + + my @hour_min = split(':', $mtime); + my $mhour = $hour_min[0]; + my $mmin = $hour_min[1]; + my $calc_time=($mhour*60)+$mmin; + if (($calc_time>=$startTime)&&($calc_time<=$endTime)) { + $value =~ s/\A0+(\d)/$1/; + $total_rain_predictions+=$value; + $total_rain_values+=1; + } + } +} + +my $result = "0.0"; + +if ($total_rain_values!=0) { + my $rain_0_100=($total_rain_predictions/$total_rain_values)*0.392156862745098; + $result = sprintf("%.2f", $rain_0_100); +} + +$url = "http://$domoticz_ip:$domoticz_port/json.htm?type=command¶m=udevice&idx=$domoticz_sensor_idx&nvalue=0&svalue=$result"; +$response = $ua->get($url); + +unless ($response->is_success) { + print "Error sending data to domoticz!\n"; + exit 0; +} +$data = $response->content; + +if (index($data, "\"OK\"") == -1) { + print "Error sending data to domoticz!\n"; + exit 0; +} + +print "OK, precip=$result\n"; diff --git a/cal_action.py b/cal_action.py new file mode 100644 index 0000000..30a5f03 --- /dev/null +++ b/cal_action.py @@ -0,0 +1,148 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + + +# il faut le module requests +# sudo pip install requests + + +# on lit le fichier genere par getgoovlecal.py +# dans le calendrier google on fait soit +# idx=etat (14=On ou 44=Off) +# +# ou idx1;idx2;idx3=etat +# 25/01/15 correction pour mode debug qui lance la cde alors que le mode ss debug non +# 25/01/15 mode auth pour identification Domoticz + + + +import time +import os +import requests +from requests.auth import HTTPBasicAuth +import csv +from collections import namedtuple +from datetime import datetime + +############# Parametres ################################# + +# fichier et chemin pour agenda +rep="/var/tmp/" +file="googlecal.txt" + +# seuil pour declemecnhemnt des actions +# c'est la tolerance autour de l'heure prevue par rapport a l'heure exacte +# cest a dire que X secondes AVANT l heure prevue on declenche +seuil=10 + +#a cause du declenchelent de crontab qui a lieu entre 0 et 5sec apres l'heure prevue +# un crontab programme toutes les minutes peut se declencher a 1min0sec, 1min1sec ,1min2sec ... 1min5sec +# donc on gere un seuil de X secondes APRES l'heure prevue +# si declenchement tt les minutes dans crontab +# si le seuil est a 10 sec +# l'action pourra se declencher 1O secondes avant +# et si c'est croontab qui declcenche on laisse 10 secondes APRES + + +#debug = 1 on affiche les chaines de caracteres recues +debug=1 + + +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# les parametres de Domoticz +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +domoticz_ip='localhost' +domoticz_port='81' +user='souti' +password='setaou' + +# l URL Domoticz est construite dans maj_switch pour allumer/eteidndre +# avec les bouts ci dessous +json_url1='/json.htm?type=command¶m=switchlight&idx=' +json_url2='&switchcmd=' +json_url3='&level=0' + +# fin du parametrage # +############### fin des parametres ############################# + +def maj_switch(idx,etat): + +#/json.htm?type=command¶m=switchlight&idx=&switchcmd=&level=0 + + requete='http://'+domoticz_ip+':'+domoticz_port+json_url1+idx+json_url2+etat+json_url3 + r=requests.get (requete,auth=HTTPBasicAuth(user,password)) + if debug!=0: + print "______________________________________________________________" + print "" + print ("URL= :",requete) + print (" le serveur Domoticz dit : ",r) + print "" + print "###############################################################" + +def debugmode(): + print "" + print "###############################################################" + print "" + print ("le fichier dit que l'action ",r.action,"debute a ",r.heuredeb,"le :",r.datedeb) + print ("heure declenchement ",heure_action) + print ("il est ",present) + print ("difference en secondes",diffsecondes) + print "" + print "" + +# main # + +reader = csv.reader(open(rep+file),delimiter='\t') +rec=namedtuple('rec','datedeb heuredeb datefin heurefin action') + +for r in map(rec._make,reader): + date_action=r.datedeb+" "+r.heuredeb + heure_action= datetime.strptime(date_action,"%Y-%m-%d %H:%M") + present=datetime.now() + diffsecondes=(heure_action-present).seconds + # diffsecondes=4 + if (diffsecondes < seuil or (diffsecondes> 86400-seuil and diffsecondes <86400)): + if debug!=0: + debugmode() + todo=r.action.split("=") + idx=todo[0] + etat=todo[1].capitalize() + + if ";" in idx: + #print "multiples idx" + midx=idx.split(";") + for each_idx in midx: + print (" IDX : ",each_idx) + if (etat=="On" or etat=="Off"): + if debug!=0: + print "" + print "ok actions a faire" + print ("idx=",each_idx) + print ("etat=",etat) + print "" + + maj_switch(each_idx,etat) + + else: + if (etat=="On" or etat=="Off"): + if debug!=0: + print "" + print "ok actions a faire" + print ("idx=",idx) + print ("etat=",etat) + print "" + + maj_switch(idx,etat) + + else: + if debug!=0: + print "Rien a faire /nothing to do/wir haben nichts damit zu tun" + debugmode() + + + + + + + diff --git a/cam.sh b/cam.sh new file mode 100755 index 0000000..54fedea --- /dev/null +++ b/cam.sh @@ -0,0 +1,11 @@ +#!/bin/bash + + DOMO_IP="localhost" # Domoticz IP Address + DOMO_PORT="81" # Domoticz Port + IDX=1148 + +movies=`find /media/WDBlue/motion/CAM1/*.avi -mmin -2|wc -l` +echo $movies +curl -y 1 -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=udevice&idx=$IDX&nvalue=0&svalue=$movies" & + +exit 0 diff --git a/changevol.sh b/changevol.sh new file mode 100755 index 0000000..ebaeaeb --- /dev/null +++ b/changevol.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +#sleep 1 + +value=`curl "http://localhost:81/json.htm?type=devices&rid=202" 2>/dev/null|grep \"Level\"|awk -F: '{print $2}' |awk -F, '{print $1}'` + + +/opt/domoticz/scripts/vol $value + +#return $value diff --git a/check.sh b/check.sh new file mode 100755 index 0000000..4ebf034 --- /dev/null +++ b/check.sh @@ -0,0 +1,45 @@ +#!/bin/bash +# Script qui vérifie l'état de domoticz et qui relance si off + +PATH=/opt/domoticz/:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin + +now=$(date) #récupération de la date et heure pour les logs +echo $now +#Récupération du retour de la commande de status +domoticz=$(/usr/sbin/service domoticz.sh status |egrep "inactive|failed" |wc -l) +echo "statut domoticz" $domoticz + +#grep "Error: RFLink: TX time out..." /var/log/domoticz.log |tail -n 1|cut -c 1-16 +#status=$(/usr/sbin/service domoticz.sh status) #On le lance + +#echo $domoticz $status +rflink=$(tail -n5000 /var/log/domoticz.log|grep -y "RFXCOM: Unhandled switch command" |wc -l) +rflink2=$(tail -n5000 /var/log/domoticz.log|grep -y "RFXCOM: TX time out..." |wc -l) +#rflink2=$(grep -y "Error: RFLink: TX time out..." /var/log/domoticz.log |wc -l) +echo "Unhandled switch" $rflink +echo "Time out" $rflink2 + +if [ "$domoticz" -ge "1" ] # Si le service n'est pas lancé +then + relance=$(/usr/sbin/service domoticz.sh restart) #On le lance + echo "$now >> relance : $relance" #On log la lancement +else + echo "$now >> Domoticz lancé" #On log l'état normal +fi + +if [ "$rflink" -ge "1" ] # Si le service n'est pas lancé +then + cat /dev/null > /var/log/domoticz.log + relance=$(/usr/sbin/service domoticz.sh restart) #On le lance + echo "$now >> relance : $relance" #On log la lancement +fi + +if [ "$rflink2" -ge "1" ] # Si le service n'est pas lancé +then + cat /dev/null > /var/log/domoticz.log + relance=$(/usr/sbin/service domoticz.sh restart) #On le lance + echo "$now >> relance rflink : $relance" #On log la lancement +fi + +exit 0 + diff --git a/check_RFXCOM.sh b/check_RFXCOM.sh new file mode 100755 index 0000000..7f50f5b --- /dev/null +++ b/check_RFXCOM.sh @@ -0,0 +1,13 @@ +#!/bin/bash + + DOMO_IP="localhost" # Domoticz IP Address + DOMO_PORT="81" # Domoticz Port + IDX=330 +export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games:/usr/local/lib/ +cnt=`tail -n50000 /var/log/domoticz.log |grep -y "Error: RFXCOM: TX time out"|wc -l` + +if [ "cnt" -gt 0 ]; then + service domoticz restart +fi + +exit 0 diff --git a/clamscan.sh b/clamscan.sh new file mode 100755 index 0000000..7bc7ea5 --- /dev/null +++ b/clamscan.sh @@ -0,0 +1,13 @@ +#!/bin/bash + + DOMO_IP="localhost" # Domoticz IP Address + DOMO_PORT="81" # Domoticz Port + IDX=330 + +nice -n 10 clamscan -r -i --max-filesize=100M --exclude "\.(CR2|TIF|tif|img|IMG|mp4|mp3|mov|flv|mkv|avi|AVI|MKV|MP4|MP3|MOV|mpg|MPG|jpg|JPG|nfo|png|PNG|html|htm|HTM|HTML|idx|gif|txt|TXT)$" --cross-fs=no /home/souti/ >/tmp/clamscanMEMUP.txt + +virus=`cat /tmp/clamscanMEMUP.txt |grep FOUND|wc -l` + +curl -y 1 -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=udevice&idx=$IDX&nvalue=0&svalue=$virus" & + +exit 0 diff --git a/clamscanWDBlue.sh b/clamscanWDBlue.sh new file mode 100755 index 0000000..2f2c786 --- /dev/null +++ b/clamscanWDBlue.sh @@ -0,0 +1,13 @@ +#!/bin/bash + + DOMO_IP="192.168.1.3" # Domoticz IP Address + DOMO_PORT="81" # Domoticz Port + IDX=331 + +nice -n 0 clamscan -r -i --max-filesize=100M --exclude "\.(CR2|cr2|info|xmp|java|class|o|epub|xml|vdi|log|img|IMG|flac|mp4|mp3|mov|flv|mkv|avi|AVI|MKV|MP4|MP3|MOV|mpg|MPG|jpg|JPG|nfo|png|PNG|html|htm|HTM|HTML|idx|gif|txt|TXT|java|php|htm|html)$" --cross-fs=no /media/Backup/ >/tmp/clamscanWDBlue.txt + +virus=`cat /tmp/clamscanWDBlue.txt |grep FOUND|wc -l` + +curl -y 1 -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=udevice&idx=$IDX&nvalue=0&svalue=$virus" & + +exit 0 diff --git a/clamscandomoticz.sh b/clamscandomoticz.sh new file mode 100755 index 0000000..493ecfc --- /dev/null +++ b/clamscandomoticz.sh @@ -0,0 +1,15 @@ +#!/bin/bash + + DOMO_IP="localhost" # Domoticz IP Address + DOMO_PORT="81" # Domoticz Port + IDX=330 + +lockfile-create --lock-name "/tmp/clamscandomoticz.lockfile" +nice -n 12 clamscan -r -i --max-filesize=100M --exclude "\.(CR2|TIF|tif|img|IMG|mp4|mp3|mov|flv|mkv|avi|AVI|MKV|MP4|MP3|MOV|mpg|MPG|jpg|JPG|nfo|png|PNG|html|htm|HTM|HTML|idx|gif|txt|TXT)$" --cross-fs=no /opt/domoticz/ >/tmp/clamscanDomoticz.txt + +virus=`cat /tmp/clamscanDomoticz.txt |grep FOUND|wc -l` + +curl -y 1 -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=udevice&idx=$IDX&nvalue=0&svalue=$virus" & + +lockfile-remove --lock-name "/tmp/clamscandomoticz.lockfile" +exit 0 diff --git a/clamscanfulldomoticz.sh b/clamscanfulldomoticz.sh new file mode 100755 index 0000000..7cbb190 --- /dev/null +++ b/clamscanfulldomoticz.sh @@ -0,0 +1,15 @@ +#!/bin/bash + + DOMO_IP="localhost" # Domoticz IP Address + DOMO_PORT="81" # Domoticz Port + IDX=330 + +lockfile-create --lock-name "/tmp/clamscanfulldomoticz.lockfile" +nice -n 12 clamscan -r -i --max-filesize=10M --exclude=/media --exclude "\.(CR2|TIF|tif|img|IMG|mp4|mp3|mov|flv|mkv|avi|AVI|MKV|MP4|MP3|MOV|mpg|MPG|jpg|JPG|nfo|png|PNG|html|htm|HTM|HTML|idx|gif|txt|TXT)$" --cross-fs=no / >/tmp/clamscanFullDomoticz.txt + +virus=`cat /tmp/clamscanFullDomoticz.txt |grep FOUND|wc -l` + +curl -y 1 -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=udevice&idx=$IDX&nvalue=0&svalue=$virus" & +lockfile-remove --lock-name "/tmp/clamscanfulldomoticz.lockfile" + +exit 0 diff --git a/clamscanpath.sh b/clamscanpath.sh new file mode 100755 index 0000000..631836d --- /dev/null +++ b/clamscanpath.sh @@ -0,0 +1,13 @@ +#!/bin/bash + + DOMO_IP="localhost" # Domoticz IP Address + DOMO_PORT="81" # Domoticz Port + IDX=330 + +nice -n 10 clamscan -r -i --max-filesize=100M --exclude "\.(CR2|TIF|tif|img|IMG|mp4|mp3|mov|flv|mkv|avi|AVI|MKV|MP4|MP3|MOV|mpg|MPG|jpg|JPG|nfo|png|PNG|html|htm|HTM|HTML|idx|gif|txt|TXT)$" --cross-fs=no $1 >/tmp/clamscanpath.txt + +virus=`cat /tmp/clamscanpath.txt |grep FOUND|wc -l` + +#curl -y 1 -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=udevice&idx=$IDX&nvalue=0&svalue=$virus" & + +exit 0 diff --git a/climOn.sh b/climOn.sh new file mode 100755 index 0000000..63e002e --- /dev/null +++ b/climOn.sh @@ -0,0 +1,5 @@ +#!/bin/sh + + +sleep 10 + diff --git a/crontab.bak b/crontab.bak new file mode 100644 index 0000000..6fe8285 --- /dev/null +++ b/crontab.bak @@ -0,0 +1,227 @@ +# DO NOT EDIT THIS FILE - edit the master and reinstall. +# (/tmp/crontab.v3hKb5/crontab installed on Wed May 20 23:29:42 2020) +# (Cron version -- $Id: crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp $) +# Edit this file to introduce tasks to be run by cron. +# +# Each task to run has to be defined through a single line +# indicating with different fields when the task will be run +# and what command to run for the task +# +# To define the time you can provide concrete values for +# minute (m), hour (h), day of month (dom), month (mon), +# and day of week (dow) or use '*' in these fields (for 'any').# +# Notice that tasks will be started based on the cron's system +# daemon's notion of time and timezones. +# +# Output of the crontab jobs (including errors) is sent through +# email to the user the crontab file belongs to (unless redirected). +# +# For example, you can run a backup of all your user accounts +# at 5 a.m every week with: +# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/ +# +# For more information see the manual pages of crontab(5) and cron(8) +# +# m h dom mon dow command + +# Edit this file to introduce tasks to be run by cron. +# +# Each task to run has to be defined through a single line +# indicating with different fields when the task will be run +# and what command to run for the task +# +# To define the time you can provide concrete values for +# minute (m), hour (h), day of month (dom), month (mon), +# and day of week (dow) or use '*' in these fields (for 'any').# +# Notice that tasks will be started based on the cron's system +# daemon's notion of time and timezones. +# +# Output of the crontab jobs (including errors) is sent through +# email to the user the crontab file belongs to (unless redirected). +# +# For example, you can run a backup of all your user accounts +# at 5 a.m every week with: +# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/ +# +# For more information see the manual pages of crontab(5) and cron(8) +# +# m h dom mon dow command +MAILTO="" + +#0 21 15 * * tar czf /tmp/sketch.tgz /home/souti/Arduino/*; cp /tmp/sketch.tgz /media/WDBlue/backup/; cp /tmp/sketch.tgz /home/souti/Google\ Drive/ +#30 21 10 * * tar czf /tmp/arduino-1.6.0.tgz /home/souti/Téléchargements/arduino-1.6.0/*; cp /tmp/arduino-1.6.0.tgz /home/souti/Google\ Drive/; mv /tmp/arduino-1.6.0.tgz /media/WDBlue/backup/ +#35 21 5 * * tar czf /tmp/arduino-1.6.5.tgz /home/souti/Téléchargements/arduino-1.6.5/*; cp /tmp/arduino-1.6.5.tgz /home/souti/Google\ Drive/; mv /tmp/arduino-1.6.5.tgz /media/WDBlue/backup/ +#05 12 1 * * cp /media/WDBlue/backup/scriptsDomoticz.tgz /home/souti/Google\ Drive/ + +0 20 20 * * rsync -arvl --size-only --bwlimit=100 /media/WDBlue/Documents /home/souti/Dropbox + +#30 20 * * * tar czf /home/souti/Google\ Drive/Arduino.tgz /home/souti/Arduino/* + +#0 20 * * * tar czf /tmp/document.tgz /home/souti/Dropbox; cp /tmp/document.tgz /home/souti/Google\ Drive/ + +#Synchro Clips +#0 09 * * * rsync -arvl --size-only --bwlimit=100 /home/souti/Musique/Clips/ /media/WDBlue/Musique/Clips/ + +#0 11 * * * rsync -arvl --size-only --bwlimit=100 /home/souti/Musique/Concerts/ /media/WDBlue/Musique/Concerts/ + +#0 12 * * * rsync -arvl --size-only --delete-during /media/Philae/Impression3D /media/WDBlue/ +#41 18 * * * rsync -arvl --size-only --delete-during --exclude=".*" /home/souti/ /media/WDBlue/Home_Souti_Akhenaton + +#*/30 * * * * scp -r souti@philae:/var/www/html/PhpTest/* /home/souti/scripts/Php/ +#5 0 * * * rsync -arvl --size-only /media/WDBlue/Musique/ /media/MEMUP/Musique/ + +#Update Clamav (Anti virus) +0 13 * * 3 /usr/bin/freshclam >> /var/log/resul_freshclam.txt + +# Scan (Anti virus) +#0 12 * * 1 clamscan -r /home/pi --cross-fs=no --detect-pua=yes >/tmp/clamscan.txt +0 13 * * 2 /opt/domoticz/scripts/clamscan.sh +0 13 * * 1 /opt/domoticz/scripts/clamscanWDBlue.sh + +10 14 * * * /opt/domoticz/scripts/prestashop.sh +# Pas besoin de le faire toutes les heures actuellement +10 12 * * * /opt/domoticz/scripts/prestashopHourly.sh + +20 20 * * * /bin/tar cvzf /media/WDBlue/backup/ImagesMyPi/Octoprint"$(date '+%Y-%m-%d')".tgz /home/souti/OctoPrint/* +30 20 * * * /bin/tar cvz --exclude=uploads --exclude=logs -f /tmp/saveOctoprintData"$(date '+%H-%m-%d')".tgz /home/souti/.octoprint/ +40 20 * * * /bin/tar cvz --exclude=uploads --exclude=logs -f /tmp/saveOctoprint2Data"$(date '+%H-%m-%d')".tgz /home/souti/.octoprint2/ + +# Mount Hackintosh +#*/5 * * * * mount_afp afp://souti:setaou@Hackintosh.home/Data/ /media/Hackintosh/ -o user=souti +#0 22 * * * rsync -arvl --size-only /media/WDBlue/Musique/ /media/Hackintosh/Musique/ +#0 22 * * * rsync -arvl --size-only /media/WDBlue/SeriesTV/ /media/Hackintosh/SeriesTV/ +#0 23 * * * rsync -arvl --size-only /media/WDBlue/StockagePhoto/ /media/Hackintosh/StockagePhoto/ +#0 04 * * * rsync -arvl --size-only /media/WDBlue/films/ /media/Hackintosh/films/ + +#0 16 * * * rsync -aP --size-only /media/Backup/backup/ /media/WDBlue/backup/ + +#epure all files +0 19 5 * * cd /media/WDBlue/backup;bash epureall.sh + + +# DOMOTICZ +# Récpératin qualité de l'air rennes +#1 */4 * * * php /opt/domoticz/scripts/qualiteAir.php + +*/5 * * * * php /opt/domoticz/scripts/suncalc.php + +# Récupération Gaz 2 et Photo par les logs serial +#* * * * * python /opt/domoticz/scripts/MySerial.py + +# Géneration des images de la terre et de la lune +#0/10 * * * * /opt/domoticz/www/templates/xplanet/xplanet_cloud.sh + +# Synchronisation de la musique sur WDRed +#42 0 * * * rsync -rltzuv --size-only --del /media/WDBlue/Musique /media/DATA/ +#0 13 * * * rsync -arvl /media/DATA/backup/ /media/WDBlue/ + +# Backup du serveur domoticz +0 2 * * * /opt/domoticz/scripts/backup/domoticz +0 3 * * * /opt/domoticz/scripts/backup/octoprint + +# Recopie de la sauvegarde de raspbmc sur wdred +#0 3 * * * scp /media/WDBlue/backup/raspbmc.img /media/WDRed/backup/ + +# Récupération agenda domoticz sur google +#remplace par un script lua 0 */2 * * * python /opt/domoticz/scripts/getgooglecal.py + +# Toutes les 10 minutes scan du fichier généré au-dessus pour lancement d'actions +#remplace par un script lua */5 * * * * python /opt/domoticz/scripts/cal_action.py + +# Script Jeedom lancé toutes les minutes ?? WTF +#* * * * * su --shell=/bin/bash - www-data -c '/usr/bin/php /usr/share/nginx/www/jeedom/core/php/jeeCron.php' >> /dev/null 2>&1 + +# Script pour récupérer la température et l'humidité du Digispark +#*/10 * * * * /opt/domoticz/scripts/hum.sh + +#Masse grasse JD +0 */4 * * * /opt/domoticz/scripts/withings.sh + +#Update Domoticz & alerte +#0 1 */7 * * /opt/domoticz/scripts/update.sh + +# read values on i2c +*/5 * * * * /opt/domoticz/scripts/i2cs2.py >/var/log/i2c.log + +# Count banned ips +*/10 * * * * /opt/domoticz/scripts/banned.sh + +# Sauvegarde home pi +#0 12 * * * tar cvzf /tmp/script.tgz --exclude '.*' --exclude '*.o' --exc$ +#30 14 * * * /etc/backup/domoticzScripts +#45 14 * * * /etc/backup/domoticzOpt +#00 15 * * * /etc/backup/domoticzWww +#0 0 * * * /usr/bin/rsync -rvl --size-only /home/pi/ /media/Backup/domot$ + + +#Ping pour garder la connexion réseau (Autre moyen ?) +#*/5 * * * * ping -c 10 192.168.0.1 2>/dev/null |grep rtt >/tmp/ping + +#*/5 * * * * mount /media/WDBlue 2>/dev/null +#*/5 * * * * mount /media/WDGreen 2>/dev/null +#*/5 * * * * mount /media/DATA 2>/dev/null +#*/5 * * * * mount /media/Backup 2>/dev/null +#*/5 * * * * mount /media/Musique 2>/dev/null +#*/5 * * * * mount /media/MEMUP 2>/dev/null + +# Check que domoticz tourne toujours +* * * * * /opt/domoticz/scripts/check.sh >>/tmp/check.log + +# Etat de la route +#*/10 8,17 * * * /opt/domoticz/scripts/infotrafic.sh +#0 8,17 * * 1,2,3,4,5 /opt/domoticz/scripts/radars.sh + + +# Etat pollen +#10 8 * * 1 /opt/domoticz/scripts/infoPollen.sh + +# Suppression des logs +0 10 * * * cd /var/log/; rm *.gz; +15 * * * * rm -rf /var/log/*.1 + +# *.[1234567890] *.log *.err syslog* samba/* faillog *.error *.old 2>/dev$ + +#Redemarrage DOMOTICZ +0 0 * * * service domoticz.sh restart + +#Test ligne +10 */2 * * * /opt/domoticz/scripts/debit.sh + +#Test ping Livebox +* * * * * /opt/domoticz/scripts/livebox2.sh +* * * * * /opt/domoticz/scripts/livebox.sh + +#Update Clamav (Anti virus) +0 13 * * 3 /usr/bin/freshclam >> /var/log/resul_freshclam.txt + +# Scan (Anti virus) +#0 12 * * 1 clamscan -r /home/pi --cross-fs=no --detect-pua=yes >/tmp/cl$ +0 1 * * * /opt/domoticz/scripts/clamscandomoticz.sh +#0 3 * * * /opt/domoticz/scripts/clamscanfulldomoticz.sh + +# Logwatch +57 8 * * * /opt/domoticz/scripts/logwatch.sh + +#* * * * * ping -c 4 orangepizero + +# Luminosite camera +#5 * * * * /usr/bin/python /opt/domoticz/scripts/lum.py + +# Epuration backup +27 7 */3 * * /media/WDBlue/backup/epureAll.sh + +# Extinction imprimante +*/10 0-6 * * * /opt/domoticz/scripts/octoprintStatus.sh >>/tmp/status.log +*/10 0-6 * * * /opt/domoticz/scripts/octoprint2Status.sh >>/tmp/status2.log + +# Synchronisation home philae sur Akhenaton +0 20 * * * /opt/domoticz/scripts/PhilaeHome.sh + +@reboot sh /opt/domoticz/scripts/mplayer.sh +@reboot /opt/ympd/ympd -w 9292 + +# Sauvegarde AcerManon +40 */3 * * 6,0 /opt/domoticz/scripts/AcerManon.sh +10 */3 * * 5 /opt/domoticz/scripts/AkhesaSouti.sh +40 */3 * * 5 /opt/domoticz/scripts/AkhesaTheo.sh + diff --git a/curl.sh b/curl.sh new file mode 100755 index 0000000..6ebd87b --- /dev/null +++ b/curl.sh @@ -0,0 +1,13 @@ +#!/bin/bash + + DOMO_IP="localhost" # Domoticz IP Address + DOMO_PORT="81" # Domoticz Port + IDX=330 + +curl_count=`ps ax |grep curl|wc -l` + +if [ "$curl_count" -gt 6 ]; then + killall curl +fi + +exit 0 diff --git a/debit.py b/debit.py new file mode 100755 index 0000000..991e73f --- /dev/null +++ b/debit.py @@ -0,0 +1,30 @@ +#!/usr/bin/python +# -*- coding: latin-1 -*- + +#sudo apt-get install python-pip +#sudo pip install speedtest-cli +#speedtest-cli --list |grep France <== Recherche serveur le plus proche + +import subprocess as sub +import os + +f = os.popen('speedtest --share --simple') +#f = open('/tmp/speedtest') +valeurvariable = f.read() + +liste = str(valeurvariable) +columns2 = liste.split(' ') +columns = [i for i in columns2 if i != ''] + +ping = str(columns[1]) +download = str(columns[3]) +upload = str(columns[5]) + +url='curl -y 2 "http://localhost:81/json.htm?type=command¶m=udevice&idx=323&nvalue=0&svalue='+ping+'"' +url1='curl -y 2 "http://localhost:81/json.htm?type=command¶m=udevice&idx=325&nvalue=0&svalue='+download+'"' +url2='curl -y 2 "http://localhost:81/json.htm?type=command¶m=udevice&idx=324&nvalue=0&svalue='+upload+'"' + +os.system(url) +os.system(url1) +os.system(url2) + diff --git a/debit.sh b/debit.sh new file mode 100755 index 0000000..09906be --- /dev/null +++ b/debit.sh @@ -0,0 +1,7 @@ +#!/bin/bash +# Script qui vérifie l'état de domoticz et qui relance si off + +export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games:/usr/local/lib/ +/usr/bin/python /opt/domoticz/scripts/debit.py + + diff --git a/digiterm b/digiterm new file mode 100755 index 0000000..de5fc36 --- /dev/null +++ b/digiterm @@ -0,0 +1,93 @@ +#!/usr/bin/env ruby +$:.unshift File.dirname(__FILE__) + "/../lib" +require 'digiusb' +require 'colored' +require 'io/console' + +if ARGV.include? '--help' or ARGV.include? '-h' + puts "Usage:" + puts " digiterm [options]" + puts " digiterm [options] [device name]" + puts + puts " Options:" + puts " --raw Disable ansi colouring and other friendly decorations." + puts " Useful for using as subprocess from another programming language." + puts " --no-wait Don't loop and wait for a digispark - return immediately if no" + puts " device is found." + puts " --no-info Don't write out any status information to standard error output" + exit +end + +raw_mode = ARGV.include?("--raw") +device_name = if ARGV.empty? or ARGV.last.start_with?("--") + false + else + ARGV.last + end +no_stderr = ARGV.include?("--no-info") + + +$stderr.puts "Looking for Digispark running DigiUSB...".blue unless no_stderr + +sleep 0.5 until DigiUSB.sparks(device_name).length > 0 unless ARGV.include? '--no-wait' +spark = DigiUSB.sparks(device_name).last + +unless spark + $stderr.puts "No device found".white_on_red unless no_stderr + exit 1 +end + +$stderr.puts "Attached to #{spark.inspect.green}".blue unless no_stderr +$stderr.puts "Type control + c to exit".blue unless no_stderr + +i = 0 +begin + loop do + char = spark.getc + if char != "" + if raw_mode + print char + else + print char.green + end + if char == "@" + loop do + char = spark.getc + if char == "" + exit 0 + end + spark.putc char + end + end + else + sleep 1.0 / 30.0 + i = i + 1 + if i > 30 + spark.putc "\n" + i = 0 + end + #$stderr.puts "s" # newline + end + + begin + char = IO.console.read_nonblock(1) + spark.putc char + rescue Errno::EAGAIN + end + end +rescue LIBUSB::ERROR_PIPE, LIBUSB::ERROR_NO_DEVICE + unless no_stderr + $stderr.puts "" # newline + $stderr.puts "Digispark disconnected".white_on_red unless no_stderr + end + exit 2 +rescue DigiUSB::ErrorCrashed + unless no_stderr + $stderr.puts "" # newline + $stderr.puts "Digispark has crashed".white_on_red + $stderr.puts " >> Probably need to call DigiUSB.refresh() more frequently in Digispark Program".blue + end + exit 3 +rescue Interrupt + $stderr.puts "" unless no_stderr +end diff --git a/digiterm.sh b/digiterm.sh new file mode 100755 index 0000000..b1a4ac0 --- /dev/null +++ b/digiterm.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +./digiterm --raw --no-info >/tmp/digiterm.tmp + +temp=`cat /tmp/digiterm.tmp |awk -F "," '{ print $2 }'|awk -F "@" '{print $1}'` +hum=`cat /tmp/digiterm.tmp |awk -F "," '{ print $1 }'|awk -F "#" '{print $2}'` + +echo $temp "--" $hum + diff --git a/domoticz.conf b/domoticz.conf new file mode 100644 index 0000000..21c385a --- /dev/null +++ b/domoticz.conf @@ -0,0 +1,105 @@ +# Domoticz configuration file + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# HTTP Listen address (default ::/0.0.0.0) +# http_address=:: + +# HTTP Listen port (default 8080, use 0 to disable HTTP) +# http_port=8080 + +# HTTPS Listen address (default ::/0.0.0.0) +# ssl_address=:: + +# HTTPS Listen port (default 443, use 0 to disable HTTP) +# ssl_port=443 + +# HTTPS root folder location +# http_root=/opt/domoticz/www + +# Web root path (for instance mydomoticz, Domoticz url will become https://127.0.0.1:8080/mydomoticz/) +# web_root=mydomoticz + +# Compression mode (on = always compress [default], off = always decompress, static = no processing but try precompressed first) +# www_compress_mode=on + +# Disable appcache, usefull for gui development +# cache=no + +# In case you forgot your admin username/password, remove the comment below. +# Do not forget to comment when you have reset your password! +# reset_password=yes + +# SSL certificate file +# ssl_cert=/opt/domoticz/server_cert.pem + +# SSL certificate key file (could also point to SSL certificate file if it contains the key) +# ssl_key=/opt/domoticz/server_cert.key + +# SSL Diffie-Hellman (DH) file (could also point to SSL certificate file if it contains the DH) +# ssl_dhparam=/opt/domoticz/server_cert.dh + +# SSL password (to access to server private key in certificatee) +# ssl_pass=secret + +# SSL method (Supported methods are: tlsv1, tlsv1_server, sslv23, sslv23_server, tlsv11, tlsv11_server, tlsv12, tlsv12_server) +# ssl_method=sslv23 + +# SSL options (default is 'efault_workarounds,no_sslv2,no_sslv3,no_tlsv1,no_tlsv1_1,single_dh_use) +# ssl_options=default_workarounds,no_sslv2,no_sslv3,no_tlsv1,no_tlsv1_1,single_dh_use' + +# Log file (for example /var/log/domoticz.log) +# log_file=/var/log/domoticz.log + +# Log level (combination of: normal,status,error,debug) +# loglevel=normal,status,error + +# Debug level (When debug level enabled, combination of: normal,hardware,received,webserver,eventsystem,python,thread_id +# debuglevel=normal,hardware + +# Disable timestamps in the log (useful with syslog, etc.) +# notimestamps=yes + +# Enable syslog as log system, specify level: user, daemon, local0 .. local7 +# syslog=user + +# Database +# dbase_file=/opt/domoticz/domoticz.db + +# Startup delay, time the daemon will pause before launching +# startup_delay=0 + +# Disable update checking +# updates=no + +# Enable PHP calls/pages, you need to have installed php-cgi +# php_cgi_path=/usr/bin/php-cgi + +# Application path (folder where domoticz is installed in) +# app_path=/opt/domoticz + +# User data path (where backups and scripts are installed) +# userdata_path=/opt/domoticz + +# Run as daemon (default when launched as service) +# daemon=yes + +# Daemon Name +# daemon_name=domoticz + +# Daemon PID file +# pidfile=/var/run/domoticz.pid + +# Launch browser (Windows only, starts a browser at startup) +# launch_browser=yes diff --git a/download_update.sh b/download_update.sh new file mode 100755 index 0000000..3edfffa --- /dev/null +++ b/download_update.sh @@ -0,0 +1,50 @@ +#!/bin/sh +cd $1 + +lowercase(){ + echo "$1" | sed "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/" +} + +OS=`lowercase \`uname -s\`` +# KERNEL=`uname -r` +MACH=`uname -m` +if [ ${MACH} = "armv6l" ] +then + MACH="armv7l" +fi + +CHANNEL="stable" +if [ "$2" = "/beta" ]; then + CHANNEL="beta" +fi + +archive_file="http://www.domoticz.com/download.php?channel=${CHANNEL}&type=release&system=${OS}&machine=${MACH}" +checksum_file="http://www.domoticz.com/download.php?channel=${CHANNEL}&type=checksum&system=${OS}&machine=${MACH}" + +# Download checksum +wget -q "${checksum_file}" -O update.tgz.sha256sum +if [ $? -ne 0 ] +then + echo "Error downloading checksum file!..."; + exit 1 +fi + +# Download archive file +wget -q "${archive_file}" -O update.tgz +if [ $? -ne 0 ] +then + echo "Error downloading archive file!..."; + exit 1 +fi + +# Check archive +if [ -f update.tgz.sha256sum ]; +then + #Check archive against checksum! + valid=$(LC_ALL=C sha256sum -c update.tgz.sha256sum | grep update.tgz | cut -d':' -f2 | tr -d ' ') + if [ $valid != "OK" ] + then + echo "Archive checksum mismatch !"; + exit 1; + fi +fi diff --git a/dzVents/.gitignore b/dzVents/.gitignore new file mode 100644 index 0000000..96200bf --- /dev/null +++ b/dzVents/.gitignore @@ -0,0 +1,8 @@ +# Created by .ignore support plugin (hsz.mobi) +/domoticzData.lua +scripts/*.lua +data/*.lua +generated_scripts/*.lua +!/runtime/tests/data/README.md +/runtime/tests/data/__data_global_data.lua +/runtime/tests/data/__data_script1.lua diff --git a/dzVents/data/README.md b/dzVents/data/README.md new file mode 100644 index 0000000..6119d30 --- /dev/null +++ b/dzVents/data/README.md @@ -0,0 +1 @@ +This folder will contains the data files for scripts. If a script uses the `data` section then dzVents stores the persistent data in this folder. If a script doesn't seem to work properly with regards to the persistent data, then you can remove the corresponding data file here. \ No newline at end of file diff --git a/dzVents/dumps/.gitignore b/dzVents/dumps/.gitignore new file mode 100644 index 0000000..5e7d273 --- /dev/null +++ b/dzVents/dumps/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/dzVents/dzVents_settings_example.lua b/dzVents/dzVents_settings_example.lua new file mode 100644 index 0000000..0ffcebc --- /dev/null +++ b/dzVents/dzVents_settings_example.lua @@ -0,0 +1,18 @@ +--[[ + Log level = 1: Errors + Log level = 1.5: Errors + info about the execution of individual scripts and a dump of the commands sent back to Domoticz + Log level = 2: Errors + info + Log level = 3: Debug info + Errors + Info (can be a lot!!!) + Log level = 0: As silent as possible + + About the fetch interval: there's no need to have a short interval in normal + situations. dzVents will only use it for battery level and some other information + that doesn't change very often. +]]-- +return { + ['Domoticz ip'] = '10.0.0.8', + ['Domoticz port'] = '8080', + ['Fetch interval'] = 'every 30 minutes', -- see readme for timer settings + ['Enable http fetch'] = true, -- only works on linux systems + ['Log level'] = 2 +} \ No newline at end of file diff --git a/dzVents/examples/calc temp delta.lua b/dzVents/examples/calc temp delta.lua new file mode 100644 index 0000000..a693bc5 --- /dev/null +++ b/dzVents/examples/calc temp delta.lua @@ -0,0 +1,22 @@ +--[[ + Assume you have two temperature sensors and a third dummy sensor that should be the + difference of these two sensors (e.g. you want to see the difference between water temperature + going into a radiator and the temperature of the water going out of it +]]-- + + +return { + active = true, + on = { + ['timer'] = {'every 5 minutes'} + }, + execute = function(domoticz) + local inTemp = domoticz.devices('Temp in').temperature + local outTemp = domoticz.devices('Temp out').temperature + local delta = outTemp - inTemp -- how much did the temperature drop? + + -- update the dummy sensor + domoticz.devices('Delta temp').updateTemperature(delta) + + end +} diff --git a/dzVents/examples/check battery levels.lua b/dzVents/examples/check battery levels.lua new file mode 100644 index 0000000..a3342d5 --- /dev/null +++ b/dzVents/examples/check battery levels.lua @@ -0,0 +1,37 @@ +local BATTERY_THRESHOLD = 10 + +return { + active = true, + on = { + ['timer'] = { + 'every hour' + } + }, + execute = function(domoticz) + + local message = '' + + -- first filter on low battery level + local lowOnBat = domoticz.devices().filter(function(device) + + local level = device.batteryLevel -- level is 0-100 + return (level ~= nil and -- not all devices have this attribute + level <= BATTERY_THRESHOLD) + + end) + + -- then loop over the results + lowOnBat.forEach(function(lowDevice) + + message = message .. 'Device ' .. + lowDevice.name .. ' is low on batteries (' .. tostring(lowDevice.batteryLevel) .. '), ' + + end) + + if (message ~= '') then + domoticz.notify('Low battery warning', message, domoticz.PRIORITY_NORMAL) + domoticz.log('Low battery warning: ' .. message, domoticz.LOG_ERROR) + end + end +} + diff --git a/dzVents/examples/check dead devices by desc.lua b/dzVents/examples/check dead devices by desc.lua new file mode 100644 index 0000000..7c9ba2e --- /dev/null +++ b/dzVents/examples/check dead devices by desc.lua @@ -0,0 +1,36 @@ +--Check dead device using their description +--This allow to configure device to be checked directly in domoticz GUI by accessing to device details and add "CDA:" +--You have to active http fetching ! +return { + active = true, + on = { + ['timer'] = { + 'every 60 minutes' + } + }, + execute = function(domoticz) + local message="" + + domoticz.devices().forEach(function(device) + if (device.description ~= nil) then + _, _, threshold = string.find(device.description,"CDA:(%d+)") + if (threshold ~= nil) then + local name = device.name + local minutes = domoticz.devices(name).lastUpdate.minutesAgo + if ( minutes > tonumber(threshold)) then + message = message .. 'Device ' .. + name .. ' seems to be dead. No heartbeat for at least ' .. + minutes .. ' minutes.\r' + end + end + + end + end) + + if (message ~= "") then + domoticz.notify('Dead devices', message, domoticz.PRIORITY_HIGH) + domoticz.log('Dead devices found: ' .. message, domoticz.LOG_ERROR) + end + + end +} diff --git a/dzVents/examples/check dead devices.lua b/dzVents/examples/check dead devices.lua new file mode 100644 index 0000000..d4de3ae --- /dev/null +++ b/dzVents/examples/check dead devices.lua @@ -0,0 +1,37 @@ + +local devicesToCheck = { + { ['name'] = 'Sensor1', ['threshold'] = 30 }, + { ['name'] = 'Sensor2', ['threshold'] = 30 }, + { ['name'] = 'Bathroom temperature', ['threshold'] = 20 } +} + +return { + active = true, + on = { + ['timer'] = { + 'every 5 minutes' + } + }, + execute = function(domoticz) + + local message = "" + + for i, deviceToCheck in pairs(devicesToCheck) do + local name = deviceToCheck['name'] + local threshold = deviceToCheck['threshold'] + local minutes = domoticz.devices(name).lastUpdate.minutesAgo + + if ( minutes > threshold) then + message = message .. 'Device ' .. + name .. ' seems to be dead. No heartbeat for at least ' .. + minutes .. ' minutes.\r' + end + end + + if (message ~= "") then + domoticz.email('Dead devices', message, 'me@address.nl') + domoticz.log('Dead devices found: ' .. message, domoticz.LOG_ERROR) + end + end +} + diff --git a/dzVents/examples/external_light.lua b/dzVents/examples/external_light.lua new file mode 100644 index 0000000..669cfb5 --- /dev/null +++ b/dzVents/examples/external_light.lua @@ -0,0 +1,22 @@ +-- External light +-- turn lights on at sunset and back off at sunrise + +return { + active = true, + on = { + timer = { + 'at sunset', + 'at sunrise' + } + }, + execute = function(domoticz, timer) + -- external light switch name + local external_light = domoticz.devices('External light') + + if (timer.trigger == 'at sunset') then + external_light.switchOn() + else + external_light.switchOff() + end + end +} diff --git a/dzVents/examples/fake presence.lua b/dzVents/examples/fake presence.lua new file mode 100644 index 0000000..4168c79 --- /dev/null +++ b/dzVents/examples/fake presence.lua @@ -0,0 +1,23 @@ +-- example script to fake the presence of people being at home + +return { + active = true, + on = { + timer = { + 'at sunset', + 'at 23:30' + } + }, + execute = function(domoticz, timer) + + if (timer.trigger == 'at sunset') then + domoticz.devices('mySwitch').switchOn() + domoticz.devices('anotherSwitch').dimTo(40) + -- add whatever you want + else + -- switch off at a random moment after 23:30 + domoticz.devices('mySwitch').switchOff().withinMin(60) + domoticz.devices('anotherSwitch').switchOff().withinMin(60) + end + end +} diff --git a/dzVents/examples/garage door.lua b/dzVents/examples/garage door.lua new file mode 100644 index 0000000..eb064ad --- /dev/null +++ b/dzVents/examples/garage door.lua @@ -0,0 +1,27 @@ +--[[ + +From the domoticz examples online: +http://www.domoticz.com/wiki/Event_script_examples + +Send a warning when the garage door has been open for more than 10 minutes + + ]] + +return { + active = true, + on = { + ['timer'] = { + 'every minute', + } + }, + execute = function(domoticz) + + local door = domoticz.devices('Garage door') + + if (door.state == 'Open' and door.lastUpdate.minutesAgo > 10) then + domoticz.notify('Garage door alert', + 'The garage door has been open for more than 10 minutes!', + domoticz.PRIORITY_HIGH) + end + end +} \ No newline at end of file diff --git a/dzVents/examples/generic.lua b/dzVents/examples/generic.lua new file mode 100644 index 0000000..10d3cad --- /dev/null +++ b/dzVents/examples/generic.lua @@ -0,0 +1,23 @@ +-- See README.md for instructions + +return { + active = false, -- set to true to activate this script + on = { + 'My switch', -- name of the device + 'My sensor_Temperature', -- better not use but check device.attributeIsChanged('temperature') + 'My sensor', + 258, -- index of the device + ['timer'] = 'every minute', -- see readme for more options and schedules + 'PIR_*', -- triggers for all devices which name begins with PIR_ + }, + + execute = function(domoticz, mySwitch) -- see readme for what you get + -- see readme for the entire domoticz object tree + -- mySwitch is a Device object with all the properties of the device that was updated + -- unless this is a timer script, then there is not second parameter to this execute function + + if (mySwitch.state == 'On') then + domoticz.notify('Hey!', 'I am on!', domoticz.PRIORITY_NORMAL) + end + end +} \ No newline at end of file diff --git a/dzVents/examples/get sensor values.lua b/dzVents/examples/get sensor values.lua new file mode 100644 index 0000000..c4063ab --- /dev/null +++ b/dzVents/examples/get sensor values.lua @@ -0,0 +1,19 @@ +return { + active = true, + on = { + devices = { + 'My sensor' + } + }, + execute = function(domoticz, mySensor) + + if (mySensor.temperature > 50) then + domoticz.notify('Hey!', 'The house might be on fire!!', + domoticz.PRIORITY_EMERGENCY, + domoticz.SOUND_SIREN) + domoticz.log('Fire alert', domoticz.LOG_ERROR) + end + + end +} + diff --git a/dzVents/examples/intruder alert.lua b/dzVents/examples/intruder alert.lua new file mode 100644 index 0000000..1ccf0a4 --- /dev/null +++ b/dzVents/examples/intruder alert.lua @@ -0,0 +1,25 @@ +return { + + active = true, + + on = { + devices = { + 'PIR_*' -- all my motion detectors' name start with PIR_ + } + }, + + execute = function(domoticz, detector) + + if (detector.state == 'Motion' and domoticz.security ~= domoticz.SECURITY_DISARMED) then + -- o dear + + domoticz.setScene('intruder alert', 'On') + + -- send notification + domoticz.notify('Security breach', '', + domoticz.PRIORITY_EMERGENCY, + domoticz.SOUND_SIREN) + end + + end +} \ No newline at end of file diff --git a/dzVents/examples/leak_detection.lua b/dzVents/examples/leak_detection.lua new file mode 100644 index 0000000..091a992 --- /dev/null +++ b/dzVents/examples/leak_detection.lua @@ -0,0 +1,72 @@ +-- Water leak detection +-- +-- assumptions: +-- need 2 devices : +-- a Water Flow devices name "Water_Flow" +-- a Dummy Device type percentage "Leakage_Percent" +-- +-- 1 / leakage "open valve" +-- Every minute if a non-zero water flow is present, it increments a counter (Leakage_Percent) +-- If the water flow is zero is that it leaks more continuously. +-- A notification can be put on "Leakage_Percent" if >80% (80% = 80 minutes of continuous flow) +-- +-- 2 / "micro continuous flow" (drip) +-- in 24 hours one must have at least 2 hours without flow (detection 0.5 liters / hour is 4.5m3 / year) +-- if not, "Leakage_Percent" is forced at 100%. + +local FLOW_DEVICE = 'Water_Flow' -- Flow device +local LEAK_DEVICE = 'Leakage_Percent' -- percent dummy device + + +return { + active = true, + on = { + ['timer'] = { + 'every minute' + } + }, + data = { + time_0_flow = { initial = 0 }, + total_time = { initial = 0 }, + }, + execute = function(domoticz) + -- Flow in liter/minute + local flow = tonumber(domoticz.devices(FLOW_DEVICE).rawData[1]) + -- Dummy device in % + local leakage = domoticz.devices(LEAK_DEVICE) + local time_with_flow = tonumber(leakage.rawData[1]) + local new_time_with_flow = time_with_flow + + -- 1 / leakage "open valve" + if (flow > 0) then + domoticz.data.time_0_flow = 0 -- there is a flow + new_time_with_flow = new_time_with_flow + 1 -- time with flow + if (new_time_with_flow > 100) then + new_time_with_flow = 100 + end + else + new_time_with_flow = 0 + domoticz.data.time_0_flow = domoticz.data.time_0_flow + 1 -- time without flow + end + + -- 2 / flight type "micro continuous flow" (drip) + domoticz.data.total_time = domoticz.data.total_time + 1 -- time without since last 2 hours with no flow + + if (domoticz.data.time_0_flow > 120) then + -- 2 hours with no flow + domoticz.data.total_time = 0 + elseif (domoticz.data.total_time > (60*24)) then + -- 24 heures since last 2 hours with no flow + new_time_with_flow = 100 + end + -- log + domoticz.log(new_time_with_flow .. ' minutes with flow ') + domoticz.log(domoticz.data.time_0_flow .. ' minutes without flow ') + domoticz.log(domoticz.data.total_time .. ' minutes without 2hrs without flow ') + + -- update dummy device % + if (time_with_flow ~= new_time_with_flow) then + leakage.update(0,new_time_with_flow) + end + end +} diff --git a/dzVents/examples/notify for dead system-alive check devices.lua b/dzVents/examples/notify for dead system-alive check devices.lua new file mode 100644 index 0000000..452a32f --- /dev/null +++ b/dzVents/examples/notify for dead system-alive check devices.lua @@ -0,0 +1,58 @@ +-- this script can be used in conjunction with the System-alive checker plug-in. +-- the plugin pings a list of devices and creates switches for these devices +-- the reason for this script is to not treat devices as dead immediately after they +-- do not respond. More often than not, the second ping atempt does work. So only +-- if the device has been not responding for a while AFTER it is been presumed dead +-- then this script will notify you + +-- put the names of these switches in the devicesToCheck list +-- you may have to tweak the THRESHOLD depending on the check interval + + + + +local THRESHOLD = 5 -- minutes +local devicesToCheck = {'ESP8266 CV', 'ESP8266 ManCave', 'ESP8266 Watermeter'} + +return { + active = true, + on = { + devices = { + devicesToCheck + }, + timer = { + 'every 5 minutes' + } + }, + data = { + notified = { initial = {} } + }, + execute = function(domoticz, item, triggerInfo) + + if (item.isTimer) then + + -- check all devices that are off and have not been updated in the past 5 minutes and have not been notified for + for index, deviceName in pairs(devicesToCheck) do + + local device = domoticz.devices(deviceName) + + if (device.state == 'Off' and + device.lastUpdate.minutesAgo >= THRESHOLD and + domoticz.data.notified[deviceName] == false) then + + domoticz.notify(deviceName .. ' is not responding anymore.',' ',domoticz.PRIORITY_HIGH) + + -- make sure we only notify once for this device in this case + domoticz.data.notified[deviceName] = true + end + end + + + else + -- it is the device that was triggered + domoticz.data.notified[item.name] = false + + end + + end +} diff --git a/dzVents/examples/only run script when button pressed.lua b/dzVents/examples/only run script when button pressed.lua new file mode 100644 index 0000000..d154184 --- /dev/null +++ b/dzVents/examples/only run script when button pressed.lua @@ -0,0 +1,23 @@ +return { + + -- create a function for the active key, when the switch in Domoticz + -- called 'script_blabla' is active, then the script is executed. + + -- Note: keep this function really light weight because it is ALWAYS + -- executed in every cycle, even when 'My switch' hasn't changed!! + + active = function(domoticz) + return (domoticz.devices('script_blabla').state == 'On') + end, + + on = { + devices = { + 'My switch' + } + }, + + execute = function(domoticz, mySwitch) + -- do some weird complicated stuff + -- that takes quite some processing time ;-) + end +} \ No newline at end of file diff --git a/dzVents/examples/plant watering notification.lua b/dzVents/examples/plant watering notification.lua new file mode 100644 index 0000000..280d347 --- /dev/null +++ b/dzVents/examples/plant watering notification.lua @@ -0,0 +1,100 @@ +--[[ + This script can be used to get notification message when plant sensor exceed specified tresholds. + It is specifically build to be used with the Xiaomi Mi Flora (https://www.domoticz.com/wiki/Mi_Flora_Bluetooth_LE), but can also be used with similar sensors + + For the script to work correctly it is recommended your device names have the following convention: + + Mi Flora - #0 Moisture + Mi Flora - #0 Conductivity + Mi Flora - #1 Moisture + etc. etc. + + This is the default device naming when Mi Flora plugin creates devices. + + If you have another naming you need to adjust settings below. +]]-- + +local configuration = { + -- Define the different sensorTypes you want to get notified of + sensorTypes = { + moisture = { + name = 'Moisture', -- Specify substring of name to match ie. "Mi Flora - #1 Moisture" + property = 'percentage' -- property of dzVents device object to use + }, + fertility = { + name = 'Conductivity', + property = 'percentage' + } + }, + + -- Define the plant names and the tresholds (min, max) per sensor below + sensor0 = { + plant = "Calamondin", + tresholds = { + moisture = {30, 60}, + fertility = {350, 2000} + } + }, + sensor1 = { + plant = "Red pepper", + tresholds = { + moisture = {15, 60}, + fertility = {350, 2000} + } + }, + sensor2 = { + plant = "Strawberries", + tresholds = { + moisture = {15, 60}, + fertility = {350, 2000} + } + }, +} + +return { + active = true, + on = { + devices = { + 'Mi Flora*' + } + }, + logging = { + level = domoticz.LOG_DEBUG + }, + execute = function(domoticz, device) + + local sensorNumber = string.match(device.name, "#(%d+)") + local configKey = 'sensor' .. sensorNumber + + if (configuration[configKey] == nil) then + domoticz.log('No configuration defined for sensor #' .. sensorNumber, domoticz.LOG_INFO) + return + end + + local sensorConfig = configuration[configKey] + local tresholds = sensorConfig.tresholds + local plantName = sensorConfig.plant + + local function checkSensorTresholds(sensorType, notification) + local sensorTypeConfig = configuration.sensorTypes[sensorType] + if (tresholds[sensorType] == nil or not string.match(device.name, sensorTypeConfig.name)) then + domoticz.log(string.format('No tresholds configured for sensor #%d or name does not match' , sensorNumber), domoticz.LOG_DEBUG) + return + end + + local value = device[sensorTypeConfig.property] + if (value < tresholds[sensorType][1] or value > tresholds[sensorType][2]) then + notification = string.format(notification, plantName) + notification = notification .. ' | ' .. string.format('%s = %d', sensorType, value) + domoticz.notify('Plants', notification) + domoticz.log(string.format('#%d %s exceeded', sensorNumber, sensorType), domoticz.LOG_DEBUG) + else + domoticz.log(string.format('#%d %s ok', sensorNumber, sensorType), domoticz.LOG_DEBUG) + end + end + + checkSensorTresholds('moisture', '%s needs watering') + checkSensorTresholds('fertility', '%s needs fertilization') + + end +} diff --git a/dzVents/examples/random night light.lua b/dzVents/examples/random night light.lua new file mode 100644 index 0000000..196c878 --- /dev/null +++ b/dzVents/examples/random night light.lua @@ -0,0 +1,24 @@ +local RANDOM_DELAY_MINS = 30 +return { + active = true, + on = { + ['timer'] = { + 'at sunset', + 'at 01:00' + } + }, + execute = function(domoticz) + + if (domoticz.security ~= domoticz.SECURITY_DISARMED) then + + local light = domoticz.devices('Window light') + + if (not light.bState) then -- i.e. state == 'On' + light.switchOn().withinMin(RANDOM_DELAY_MINS) + else + light.switchOff().withinMin(RANDOM_DELAY_MINS) + end + + end + end +} diff --git a/dzVents/examples/respond to switch.lua b/dzVents/examples/respond to switch.lua new file mode 100644 index 0000000..22326b9 --- /dev/null +++ b/dzVents/examples/respond to switch.lua @@ -0,0 +1,14 @@ +return { + active = true, + on = { + devices = { + 'My switch' + } + }, + + execute = function(domoticz, mySwitch) + if (mySwitch.state == 'On') then + domoticz.notify('Hey!', 'I am on!', domoticz.PRIORITY_NORMAL) + end + end +} diff --git a/dzVents/examples/schedule fish pond pump.lua b/dzVents/examples/schedule fish pond pump.lua new file mode 100644 index 0000000..b56c927 --- /dev/null +++ b/dzVents/examples/schedule fish pond pump.lua @@ -0,0 +1,20 @@ +return { + active = true, + on = { + ['timer'] = { + 'at 8:30 on mon,tue,wed,thu,fri', + 'at 17:30 on mon,tue,wed,thu,fri', + + -- weeekends are different + 'at sunset on sat, sun', + 'at sunrise on sat, sun' + } + }, + + execute = function(domoticz) + + local pump = domoticz.devices('Pond') + pump.toggleSwitch() + + end +} diff --git a/dzVents/examples/simple room heating with hysteresis control.lua b/dzVents/examples/simple room heating with hysteresis control.lua new file mode 100644 index 0000000..eb34e6b --- /dev/null +++ b/dzVents/examples/simple room heating with hysteresis control.lua @@ -0,0 +1,96 @@ +-- assumptions: +-- the setpoint is set by a selector dummy device where the values are numeric temperatures +-- but you can easily change it to a setpoint device + +local BOILER_DEVICE = 'Boiler' -- switch device +local SETPOINT_DEVICE = 'Setpoint' -- selector dummy device +local TEMPERATURE_SENSOR = 'Temperature' +local HYSTERESIS = 0.5 -- temp has to drop this value below setpoint before boiler is on again +local SMOOTH_FACTOR = 3 +local LOGGING = true + +return { + on = { + ['timer'] = { + 'every minute', + }, + devices = { + TEMPERATURE_SENSOR, + SETPOINT_DEVICE + } + }, + data = { + temperatureReadings = { history = true, maxItems = SMOOTH_FACTOR } + }, + active = true, + execute = function(domoticz, item) + + local avgTemp + local temperatureReadings = domoticz.data.temperatureReadings + local sensor = domoticz.devices(TEMPERATURE_SENSOR) + local current = sensor.temperature + local boiler = domoticz.devices(BOILER_DEVICE) + local setpoint = domoticz.devices(SETPOINT_DEVICE) + + -- first check if the sensor got a new reading or the setpoint was changed: + if (item.isDevice) then + + if (sensor.changed) then + -- sensor just reported a new reading + -- add it to the readings table + + if (current ~= 0 and current ~= nil) then + temperatureReadings.add(current) + else + -- no need to be here, weird state detected + domoticz.log('Strange sensor reading.. skiping', domoticz.LOG_ERROR) + return + end + + elseif (domoticz.devices(SETPOINT_DEVICE).changed) then + -- a new setpoint was set + if LOGGING then domoticz.log('Setpoint was set to ' .. item.state) end + else + -- no business here, bail out... + return + end + end + + -- now determine what to do + if (setpoint.state == nil or setpoint.state == 'Off') then + boiler.switchOff() + return -- we're done here + end + + local setpointValue = tonumber(setpoint.state) + + -- determine at which temperature the boiler should be + -- switched on + local switchOnTemp = setpointValue - HYSTERESIS + + -- don't use the current reading but average it out over + -- the past readings (data smoothing) to get rid of noise, wrong readings etc + local avgTemp = temperatureReadings.avg(1, SMOOTH_FACTOR, current) -- fallback to current when history is empty + + if LOGGING then + domoticz.log('Average: ' .. avgTemp, domoticz.LOG_INFO) + domoticz.log('Setpoint: ' .. setpointValue, domoticz.LOG_INFO) + domoticz.log('Current boiler state: ' .. boiler.state, domoticz.LOG_INFO) + domoticz.log('Switch-on temperature: ' .. switchOnTemp, domoticz.LOG_INFO) + end + + if (avgTemp >= setpointValue and boiler.state == 'On') then + if LOGGING then domoticz.log('Target temperature reached, boiler off') end + boiler.switchOff() + end + + if (avgTemp < setpointValue and boiler.state == 'Off') then + if (avgTemp < switchOnTemp) then + if LOGGING then domoticz.log('Heating is required, boiler switched on') end + boiler.switchOn() + else + if LOGGING then domoticz.log('Average temperature below setpoint but within hysteresis range, waiting for temperature to drop to ' .. switchOnTemp) end + end + end + end +} diff --git a/dzVents/examples/sunscreen.lua b/dzVents/examples/sunscreen.lua new file mode 100644 index 0000000..6594c27 --- /dev/null +++ b/dzVents/examples/sunscreen.lua @@ -0,0 +1,132 @@ +-- Define all the sensors which needs to be considered for the sunscreen to close +local sensors = { + temperature = { + active = true, + device = 'Temperature', + closeRule = function(device) + return device.temperature <= 15 + end + }, + wind = { + active = true, + device = 'Wind', + closeRule = function(device) + return device.speed >= 50 or device.gust >= 150 + end + }, + rain = { + active = true, + device = 'Rain', + closeRule = function(device) + return device.rainRate > 0 + end + }, + rainExpected = { + active = false, + device = 'Rain expected', -- This needs to be a virtual sensor of type 'percentage' + closeRule = function(device) + return device.percentage > 15 + end + }, + uv = { + active = true, + device = 'UV', + closeRule = function(device) + return device.uv <= 3 + end + }, + lux = { + active = false, + device = 'Lux', + closeRule = function(device) + return device.lux <= 500 + end + } +} + +-- Define the name of your sunscreen device +local sunscreenDevice = 'Sunscreen' + +-- Enable dry run mode to test the sunscreen script without actually activating the sunscreen +local dryRun = false + +-- Define the name of a virtual switch which you can use to disable the sunscreen automation script +-- Set to false to disable this feature +local manualOverrideSwitch = false + +-- Minutes to wait after a sunscreen close before opening it again. +local timeBetweenOpens = 10 + +return { + active = true, + on = { + timer = {'every minute'} + }, + logging = { + level = domoticz.LOG_DEBUG, + marker = 'Sunscreen' + }, + execute = function(domoticz) + + local function switchOn(sunscreen, message) + if (sunscreen.state == 'Closed') then + if (not dryRun) then + sunscreen.switchOn() + domoticz.notify('Sunscreen', message) + end + domoticz.log(message, domoticz.LOG_INFO) + end + end + + local function switchOff(sunscreen, message) + if (sunscreen.state == 'Open') then + if (not dryRun) then + sunscreen.switchOff() + domoticz.notify('Sunscreen', message) + end + domoticz.log(message, domoticz.LOG_INFO) + end + end + + if (manualOverrideSwitch and domoticz.devices(manualOverrideSwitch).state == 'On') then + domoticz.log('Automatic sunscreen script is manually disabled', domoticz.LOG_DEBUG) + return + end + + local sunscreen = domoticz.devices(sunscreenDevice) + + -- Sunscreen must always be up during nighttime + if (domoticz.time.isNightTime) then + switchOff(sunscreen, 'Closing sunscreen, It is night') + return + end + + -- Check all sensor tresholds and if any exeeded close sunscreen + for sensorType, sensor in pairs(sensors) do + + if (sensor['active'] == true) then + + local device = domoticz.devices(sensor['device']) + local closeRule = sensor['closeRule'] + + domoticz.log('Checking sensor: ' .. sensorType, domoticz.LOG_DEBUG) + + if (closeRule(device)) then + + switchOff(sunscreen, sensorType .. ' treshold exceeded, Sunscreen up') + + domoticz.log(sensorType .. ' treshold exceeded', domoticz.LOG_DEBUG) + -- Return early when we exeed any tresholds + return + end + else + domoticz.log('Sensor not active skipping: ' .. sensorType, domoticz.LOG_DEBUG) + end + end + + -- All tresholds OK, sunscreen may be lowered + if (sunscreen.lastUpdate.minutesAgo > timeBetweenOpens) then + switchOn(sunscreen, 'Sun is shining, all thresholds OK, lowering sunscreen') + end + end +} diff --git a/dzVents/examples/templates/All.lua b/dzVents/examples/templates/All.lua new file mode 100644 index 0000000..5ab866b --- /dev/null +++ b/dzVents/examples/templates/All.lua @@ -0,0 +1,119 @@ +-- Check the wiki for dzVents +-- remove what you don't need +return { + + -- optional active section, + -- when left out the script is active + -- note that you still have to check this script + -- as active in the side panel + active = { + + true, -- either true or false, or you can specify a function + + --function(domoticz) + -- return true/false + --end + }, + -- trigger + -- can be a combination: + on = { + + -- device triggers + devices = { + -- scripts is executed if the device that was updated matches with one of these triggers + 'device name', -- device name + 'abc*', -- triggers for all devices which name begins with abc + 258, -- id + }, + + -- timer riggers + timer = { + -- timer triggers.. if one matches with the current time then the script is executed + 'at 13:45', + 'at 18:37', + 'every 3 minutes on mon,tue,fri at 16:00-15:00', + function(domoticz) + -- return true or false + end + }, + + -- user variable triggers + variables = { + 'myUserVariable' + }, + + -- security triggers + security = { + domoticz.SECURITY_ARMEDAWAY, + domoticz.SECURITY_ARMEHOME, + }, + + -- scene triggers + scenes = { + 'myScene' + }, + + -- group triggers + groups = { + 'myGroup' + }, + + -- http http responses + httpResponses = { + 'some callback string' + }, + + -- system events + system = { + 'start', + 'stop', + 'manualBackupFinished', + 'dailyBackupFinished', + 'hourlyBackupFinished', + 'monthlyBackupFinished' + }, + + customEvents = { + 'myCustomEvent' + } + }, + + -- persistent data + -- see documentation about persistent variables + data = { + myVar = { initial = 5 }, + myHistoryVar = { maxItems = 10 }, + }, + + -- custom logging level for this script + logging = { + level = domoticz.LOG_DEBUG, + marker = "Cool script" + }, + + -- actual event code + -- the second parameter is depending on the trigger + -- when it is a device change, the second parameter is the device object + -- similar for variables, scenes and groups and httpResponses + -- inspect the type like: triggeredItem.isDevice + execute = function(domoticz, triggeredItem, info) + --[[ + + The domoticz object holds all information about your Domoticz system. E.g.: + + local myDevice = domoticz.devices('myDevice') + local myVariable = domoticz.variables('myUserVariable') + local myGroup = domoticz.groups('myGroup') + local myScene = domoticz.scenes('myScene') + + The device object is the device that was triggered due to the device in the 'on' section above. + ]] -- + + -- example + + if (triggerdItem.active) then -- state == 'On' + triggerdItem.switchOff().afterMin(2) -- if it is a switch + domoticz.notify('Light info', 'The light ' .. triggerdItem.name .. ' will be switched off soon') + end + end +} diff --git a/dzVents/examples/templates/Bare.lua b/dzVents/examples/templates/Bare.lua new file mode 100644 index 0000000..ec0b8f0 --- /dev/null +++ b/dzVents/examples/templates/Bare.lua @@ -0,0 +1,18 @@ +return { + on = { + devices = {}, + timer = {}, + variables = {}, + scenes = {}, + groups = {}, + security = {}, + httpResponses = {}, + customEvents = {}, + system = {}, + }, + data = {}, + logging = {}, + execute = function(domoticz, triggeredItem) + + end +} diff --git a/dzVents/examples/templates/CustomEvents.lua b/dzVents/examples/templates/CustomEvents.lua new file mode 100644 index 0000000..30f2765 --- /dev/null +++ b/dzVents/examples/templates/CustomEvents.lua @@ -0,0 +1,20 @@ +return { + on = { + timer = { + 'every 5 minutes' -- just an example to trigger the event + }, + customEvents = { + 'MyEvent' -- event triggered by emitEvent + } + }, + data = {}, + logging = {}, + execute = function(domoticz, triggeredItem) + if (triggeredItem.isCustomEvent) then + domoticz.utils._.print(triggeredItem.data) + else + -- second parameter can be anything, number, string, boolean or table + domoticz.emitEvent('MyEvent', 'Some data') + end + end +} diff --git a/dzVents/examples/templates/Device.lua b/dzVents/examples/templates/Device.lua new file mode 100644 index 0000000..d09f28e --- /dev/null +++ b/dzVents/examples/templates/Device.lua @@ -0,0 +1,10 @@ +return { + on = { + devices = { + 'myDevice' + } + }, + execute = function(domoticz, device) + domoticz.log('Device ' .. device.name .. ' was changed', domoticz.LOG_INFO) + end +} \ No newline at end of file diff --git a/dzVents/examples/templates/Group.lua b/dzVents/examples/templates/Group.lua new file mode 100644 index 0000000..84cd2b9 --- /dev/null +++ b/dzVents/examples/templates/Group.lua @@ -0,0 +1,10 @@ +return { + on = { + groups = { + 'myGroup' + } + }, + execute = function(domoticz, group) + domoticz.log('Group ' .. group.name .. ' was changed', domoticz.LOG_INFO) + end +} \ No newline at end of file diff --git a/dzVents/examples/templates/HTTPRequest.lua b/dzVents/examples/templates/HTTPRequest.lua new file mode 100644 index 0000000..556dc52 --- /dev/null +++ b/dzVents/examples/templates/HTTPRequest.lua @@ -0,0 +1,38 @@ +return { + on = { + timer = { + 'every 5 minutes' -- just an example to trigger the request + }, + httpResponses = { + 'trigger' -- must match with the callback passed to the openURL command + } + }, + execute = function(domoticz, item) + + if (item.isTimer) then + domoticz.openURL({ + url = 'http://somedomain/someAPI?param=1', + method = 'GET', + callback = 'trigger', -- see httpResponses above. + }) + end + + if (item.isHTTPResponse) then + + if (item.ok) then + if (item.isJSON) then + + local someValue = item.json.someValue -- just an example + + -- update some device in Domoticz + domoticz.devices('myTextDevice').updateText(someValue) + end + else + domoticz.log('There was a problem handling the request', domoticz.LOG_ERROR) + domoticz.log(item, domoticz.LOG_ERROR) + end + + end + + end +} diff --git a/dzVents/examples/templates/Scene.lua b/dzVents/examples/templates/Scene.lua new file mode 100644 index 0000000..f5566b1 --- /dev/null +++ b/dzVents/examples/templates/Scene.lua @@ -0,0 +1,10 @@ +return { + on = { + scenes = { + 'myScene' + } + }, + execute = function(domoticz, scene) + domoticz.log('Scene ' .. scene.name .. ' was changed', domoticz.LOG_INFO) + end +} \ No newline at end of file diff --git a/dzVents/examples/templates/Security.lua b/dzVents/examples/templates/Security.lua new file mode 100644 index 0000000..86dec55 --- /dev/null +++ b/dzVents/examples/templates/Security.lua @@ -0,0 +1,10 @@ +return { + on = { + security = { + domoticz.SECURITY_ARMEDAWAY, + } + }, + execute = function(domoticz, security) + domoticz.log('Security was triggered by ' .. security.trigger, domoticz.LOG_INFO) + end +} diff --git a/dzVents/examples/templates/System.lua b/dzVents/examples/templates/System.lua new file mode 100644 index 0000000..0c54a10 --- /dev/null +++ b/dzVents/examples/templates/System.lua @@ -0,0 +1,17 @@ +return { + on = { + system = { + 'start', + 'stop', + 'manualBackupFinished', + 'dailyBackupFinished', + 'hourlyBackupFinished', + 'monthlyBackupFinished' + } + }, + data = {}, + logger = {}, + execute = function(domoticz, triggeredItem) + domoticz.log('Domoticz has started') + end +} diff --git a/dzVents/examples/templates/Timer.lua b/dzVents/examples/templates/Timer.lua new file mode 100644 index 0000000..d17fd5d --- /dev/null +++ b/dzVents/examples/templates/Timer.lua @@ -0,0 +1,50 @@ +return { + on = { + timer = { + 'every minute', -- causes the script to be called every minute + 'every other minute', -- minutes: xx:00, xx:02, xx:04, ..., xx:58 + 'every minutes', -- starting from xx:00 triggers every xx minutes (0 > xx < 60) + 'every hour', -- 00:00, 01:00, ..., 23:00 (24x per 24hrs) + 'every other hour', -- 00:00, 02:00, ..., 22:00 (12x per 24hrs) + 'every hours', -- starting from 00:00, triggers every xx hours (0 > xx < 24) + 'at 13:45', -- specific time + 'at *:45', -- every 45th minute in the hour + 'at 15:*', -- every minute between 15:00 and 16:00 + 'at 12:45-21:15', -- between 12:45 and 21:15. You cannot use '*'! + 'at 19:30-08:20', -- between 19:30 and 8:20 then next day + 'at 13:45 on mon,tue', -- at 13:45 only on Monday en Tuesday (english) + 'every hour on sat', -- you guessed it correctly + 'at sunset', -- uses sunset/sunrise info from Domoticz + 'at sunrise', + 'at sunset on sat,sun', + 'xx minutes before sunset', + 'xx minutes after sunset', + 'xx minutes before sunrise', + 'xx minutes after sunrise', -- guess ;-) + 'between aa and bb', -- aa/bb can be a time stamp like 15:44 + -- aa/bb can be sunrise/sunset + -- aa/bb can be 'xx minutes before/after + -- sunrise/sunset' + 'at nighttime', -- between sunset and sunrise + 'at daytime', -- between sunrise and sunset + 'at civildaytime', -- between civil twilight start and civil twilight end + 'at civilnighttime', -- between civil twilight end and civil twilight start + 'at daytime on mon,tue', -- between sunrise and sunset only on monday and tuesday + + -- or if you want to go really wild: + 'at nighttime at 21:32-05:44 every 5 minutes on sat, sun', + 'every 10 minutes between 20 minutes before sunset and 30 minutes after sunrise on mon,fri,tue', + + -- or just do it yourself: + function(domoticz) + -- you can use domoticz.time to get the current time + -- note that this function is called every minute! + -- custom code that either returns true or false + return true + end, + } + }, + execute = function(domoticz, timer) + domoticz.log('Timer event was triggered by ' .. timer.trigger, domoticz.LOG_INFO) + end +} diff --git a/dzVents/examples/templates/UserVariable.lua b/dzVents/examples/templates/UserVariable.lua new file mode 100644 index 0000000..8b7d66a --- /dev/null +++ b/dzVents/examples/templates/UserVariable.lua @@ -0,0 +1,11 @@ +return { + on = { + variables = { + 'myUserVariable' + } + }, + execute = function(domoticz, variable) + domoticz.log('Variable ' .. variable.name .. ' was changed', domoticz.LOG_INFO) + -- code + end +} \ No newline at end of file diff --git a/dzVents/examples/templates/bare.lua b/dzVents/examples/templates/bare.lua new file mode 100644 index 0000000..5ab3e49 --- /dev/null +++ b/dzVents/examples/templates/bare.lua @@ -0,0 +1,16 @@ +return { + on = { + devices = {}, + timer = {}, + variables = {}, + scenes = {}, + groups = {}, + security = {}, + httpResponses = {} + }, + data = {}, + logger = {}, + execute = function(domoticz, triggeredItem) + + end +} diff --git a/dzVents/examples/templates/complete.lua b/dzVents/examples/templates/complete.lua new file mode 100644 index 0000000..9a2d2d3 --- /dev/null +++ b/dzVents/examples/templates/complete.lua @@ -0,0 +1,105 @@ +-- Check the wiki for dzVents +-- remove what you don't need +return { + + -- optional active section, + -- when left out the script is active + -- note that you still have to check this script + -- as active in the side panel + active = { + + true, -- either true or false, or you can specify a function + + --function(domoticz) + -- return true/false + --end + } + -- trigger + -- can be a combination: + on = { + + -- device triggers + devices = { + -- scripts is executed if the device that was updated matches with one of these triggers + 'device name', -- device name + 'abc*', -- triggers for all devices which name begins with abc + 258, -- id + }, + + -- timer riggers + timer = { + -- timer triggers.. if one matches with the current time then the script is executed + 'at 13:45', + 'at 18:37', + 'every 3 minutes on mon,tue,fri at 16:00-15:00', + function(domoticz) + -- return true or false + end + }, + + -- user variable triggers + variables = { + 'myUserVariable' + }, + + -- security triggers + security = { + domoticz.SECURITY_ARMEDAWAY, + domoticz.SECURITY_ARMEHOME, + }, + + -- scene triggers + scenes = { + 'myScene' + }, + + -- group triggers + groups = { + 'myGroup' + }, + + -- http http responses + httpResponses = { + 'some callback string' + } + }, + + -- persistent data + -- see documentation about persistent variables + data = { + myVar = { initial = 5 }, + myHistoryVar = { maxItems = 10 }, + }, + + -- custom logging level for this script + logging = { + level = domoticz.LOG_DEBUG, + marker = "Cool script" + }, + + -- actual event code + -- the second parameter is depending on the trigger + -- when it is a device change, the second parameter is the device object + -- similar for variables, scenes and groups and httpResponses + -- inspect the type like: triggeredItem.isDevice + execute = function(domoticz, triggeredItem, info) + --[[ + + The domoticz object holds all information about your Domoticz system. E.g.: + + local myDevice = domoticz.devices('myDevice') + local myVariable = domoticz.variables('myUserVariable') + local myGroup = domoticz.groups('myGroup') + local myScene = domoticz.scenes('myScene') + + The device object is the device that was triggered due to the device in the 'on' section above. + ]] -- + + -- example + + if (triggerdItem.active) then -- state == 'On' + triggerdItem.switchOff().afterMin(2) -- if it is a switch + domoticz.notify('Light info', 'The light ' .. triggerdItem.name .. ' will be switched off soon') + end + end +} diff --git a/dzVents/examples/templates/device.lua b/dzVents/examples/templates/device.lua new file mode 100644 index 0000000..75ecfff --- /dev/null +++ b/dzVents/examples/templates/device.lua @@ -0,0 +1,10 @@ +return { + on = { + devices = { + 'myDevice' + } + }, + execute = function(domoticz, device) + domoticz.log('Device ' .. device.name .. ' was changed', domoticz.LOG_INFO) + end +} diff --git a/dzVents/examples/templates/global_data.lua b/dzVents/examples/templates/global_data.lua new file mode 100644 index 0000000..4a94f25 --- /dev/null +++ b/dzVents/examples/templates/global_data.lua @@ -0,0 +1,18 @@ +-- this scripts holds all the globally persistent variables and helper functions +-- see the documentation in the wiki +-- NOTE: +-- THERE CAN BE ONLY ONE global_data SCRIPT in your Domoticz install. + +return { + -- global persistent data + data = { + myGlobalVar = { initial = 12 } + }, + + -- global helper functions + helpers = { + myHelperFunction = function(domoticz) + -- code + end + } +} diff --git a/dzVents/examples/templates/group.lua b/dzVents/examples/templates/group.lua new file mode 100644 index 0000000..84cd2b9 --- /dev/null +++ b/dzVents/examples/templates/group.lua @@ -0,0 +1,10 @@ +return { + on = { + groups = { + 'myGroup' + } + }, + execute = function(domoticz, group) + domoticz.log('Group ' .. group.name .. ' was changed', domoticz.LOG_INFO) + end +} \ No newline at end of file diff --git a/dzVents/examples/templates/scene.lua b/dzVents/examples/templates/scene.lua new file mode 100644 index 0000000..f5566b1 --- /dev/null +++ b/dzVents/examples/templates/scene.lua @@ -0,0 +1,10 @@ +return { + on = { + scenes = { + 'myScene' + } + }, + execute = function(domoticz, scene) + domoticz.log('Scene ' .. scene.name .. ' was changed', domoticz.LOG_INFO) + end +} \ No newline at end of file diff --git a/dzVents/examples/templates/security.lua b/dzVents/examples/templates/security.lua new file mode 100644 index 0000000..75b0ba6 --- /dev/null +++ b/dzVents/examples/templates/security.lua @@ -0,0 +1,10 @@ +return { + on = { + security = { + domoticz.SECURITY_ARMEDAWAY, + } + }, + execute = function(domoticz, security, info) + domoticz.log('Security was triggered by ' .. security.trigger, domoticz.LOG_INFO) + end +} diff --git a/dzVents/examples/templates/timer.lua b/dzVents/examples/templates/timer.lua new file mode 100644 index 0000000..1225691 --- /dev/null +++ b/dzVents/examples/templates/timer.lua @@ -0,0 +1,53 @@ +return { + on = { + timer = { + 'every minute', -- causes the script to be called every minute + 'every other minute', -- minutes: xx:00, xx:02, xx:04, ..., xx:58 + 'every minutes', -- starting from xx:00 triggers every xx minutes + -- (0 > xx < 60) + 'every hour', -- 00:00, 01:00, ..., 23:00 (24x per 24hrs) + 'every other hour', -- 00:00, 02:00, ..., 22:00 (12x per 24hrs) + 'every hours', -- starting from 00:00, triggers every xx + -- hours (0 > xx < 24) + 'at 13:45', -- specific time + 'at *:45', -- every 45th minute in the hour + 'at 15:*', -- every minute between 15:00 and 16:00 + 'at 12:45-21:15', -- between 12:45 and 21:15. You cannot use '*'! + 'at 19:30-08:20', -- between 19:30 and 8:20 then next day + 'at 13:45 on mon,tue', -- at 13:45 only on Monday en Tuesday (english) + 'every hour on sat', -- you guessed it correctly + 'at sunset', -- uses sunset/sunrise info from Domoticz + 'at sunrise', + 'at sunset on sat,sun', + 'xx minutes before sunset', + 'xx minutes after sunset', + 'xx minutes before sunrise', + 'xx minutes after sunrise', -- guess ;-) + 'between aa and bb', -- aa/bb can be a time stamp like 15:44 + -- aa/bb can be sunrise/sunset + -- aa/bb can be 'xx minutes before/after + -- sunrise/sunset' + 'at nighttime', -- between sunset and sunrise + 'at daytime', -- between sunrise and sunset + 'at civildaytime', -- between civil twilight start and civil twilight end + 'at civilnighttime', -- between civil twilight end and civil twilight startœ + 'at daytime on mon,tue', -- between sunrise and sunset + -- only on monday and tuesday + + -- or if you want to go really wild: + 'at nighttime at 21:32-05:44 every 5 minutes on sat, sun', + 'every 10 minutes between 20 minutes before sunset and 30 minutes after sunrise on mon,fri,tue', + + -- or just do it yourself: + function(domoticz) + -- you can use domoticz.time to get the current time + -- note that this function is called every minute! + -- custom code that either returns true or false + return true + end + }, + }, + execute = function(domoticz, timer) + domoticz.log('Timer event was triggered by ' .. timer.trigger, domoticz.LOG_INFO) + end +} diff --git a/dzVents/examples/templates/variable.lua b/dzVents/examples/templates/variable.lua new file mode 100644 index 0000000..3d825f4 --- /dev/null +++ b/dzVents/examples/templates/variable.lua @@ -0,0 +1,11 @@ +return { + on = { + variables = { + 'myUserVariable' + } + }, + execute = function(domoticz, variable) + domoticz.log('Variable ' .. variable.name .. ' was changed', domoticz.LOG_INFO) + -- code + end +} diff --git a/dzVents/generated_scripts/README.md b/dzVents/generated_scripts/README.md new file mode 100644 index 0000000..2627dcc --- /dev/null +++ b/dzVents/generated_scripts/README.md @@ -0,0 +1,3 @@ +This folder will contain scripts that are created inside Domoticz using +the internal script editor. Don't remove this folder and do not edit the scripts in +here as they will be overwritten. \ No newline at end of file diff --git a/dzVents/scripts/README.md b/dzVents/scripts/README.md new file mode 100644 index 0000000..f422315 --- /dev/null +++ b/dzVents/scripts/README.md @@ -0,0 +1,3 @@ +**Scripts folder** + +Place all your scripts in this folder. Only these scripts will be executed by dzVents. See the example folder for some script examples and check the README.md in the root for instructions. \ No newline at end of file diff --git a/dzVents/scripts/livebox.old b/dzVents/scripts/livebox.old new file mode 100644 index 0000000..8ce0cc2 --- /dev/null +++ b/dzVents/scripts/livebox.old @@ -0,0 +1,486 @@ +--[[ + Prérequis : + Domoticz v3.8837 or later (dzVents version 2.4 or later) + + Sources : https://www.alex-braga.fr/ressources_externe/xdslbox_3.4.10.sh + https://github.com/rene-d/sysbus + https://github.com/NextDom/plugin-livebox/ + + Livebox 4 stats + + https://easydomoticz.com/forum/viewtopic.php?f=17&t=7247 + https://github.com/papo-o/domoticz_scripts/new/master/dzVents/scripts/livebox.lua + https://pon.fr/dzvents-toutes-les-infos-de-la-livebox-en-un-seul-script/ + +-- Authors ---------------------------------------------------------------- + V1.0 - Neutrino - Domoticz + V1.1 - Neutrino - Activation/désactivation du WiFi + V1.2 - papoo - Liste des n derniers appels manqués, sans réponse, réussis et surveillance périphériques des connectés/déconnectés + V1.3 - Neutrino - Possibilité de purger le journal d'appels + V1.4 - papoo - Possibilité de rebooter la Livebox + V1.5 - papoo - Correction non mise à jour des devices après RAZ de la liste des appels + V1.6 - papoo - Correction horodatage heures d'appel à GMT+2 + V1.7 - papoo - Affichage des noms connus via fichiers de contacts +]]-- +-- Variables à modifier ------------------------------------------------ + +local fetchIntervalMins = 3 -- intervalle de mise à jour. +local adresseLB = '192.168.1.1' --Adresse IP de votre Livebox 4 +local password = "jefa6jyu" +local tmpDir = "/var/tmp" --répertoire temporaire, dans l'idéal en RAM +local myOutput=tmpDir.."/Output.txt" +local myCookies=tmpDir.."/Cookies.txt" + +-- Domoticz devices +local SyncATM = nil --"Sync ATM" -- Nom du capteur custom Synchro ATM down, nil si non utilisé +local SyncATMup = nil --"Sync ATM up" -- Nom du capteur custom Synchro ATM up, nil si non utilisé +local Attn = nil --"Attn" -- Nom du capteur custom Attenuation de la ligne, nil si non utilisé +local MargedAttn = nil --"Marge d'Attn" -- Nom du capteur custom Marge d'atténuation, nil si non utilisé +local IPWAN = nil --"IP WAN" -- Nom du capteur Text IP WAN, nil si non utilisé +local IPv6WAN = nil --"IPv6 WAN" -- Nom du capteur Text IPv6 WAN, nil si non utilisé +local DernierAppel = "Dernier Appel" -- Nom du capteur Text Dernier Appel, nil si non utilisé +local UptimeLB = nil -- "Uptime Livebox" -- Nom du capteur Text Uptime Livebox, nil si non utilisé +local TransmitBlocks = nil --"TransmitBlocks" -- Nom du capteur Incremental Counter TransmitBlocks, nil si non utilisé +local ReceiveBlocks = nil --"ReceiveBlocks" -- Nom du capteur Incremental Counter ReceiveBlocks, nil si non utilisé +local internet = nil --"Internet" -- Nom du capteur Interrupteur Internet, nil si non utilisé +local VoIP = nil --"VoIP" -- Nom du capteur Interrupteur VoIP, nil si non utilisé +local ServiceTV = nil --"Service TV" -- Nom du capteur Interrupteur Service TV, nil si non utilisé +local wifi24 = nil --"WiFi 2.4" -- Nom du capteur Interrupteur wifi 2.4Ghz, nil si non utilisé +local wifi5 = nil --"WiFi 5" -- Nom du capteur Interrupteur wifi 5Ghz, nil si non utilisé +local missedCall = "Appels manqués" -- Nom du capteur Text appels manqués, nil si non utilisé +local nbMissedCall = 4 -- Nombre d'appels manqués à afficher +local failedCall = "Appels sans réponse" -- Nom du capteur Text appels sans réponse, nil si non utilisé +local nbFailedCall = 4 -- Nombre d'appels sans réponse à afficher +local succeededCall = nil -- "Appels Réussis" -- Nom du capteur Text appels réussis, nil si non utilisé +local nbSucceededCall = 4 -- Nombre d'appels réussis à afficher +local clearCallList = "Effacer liste appels" -- Nom du capteur Interrupteur PushOn clearCallList +local reboot = 1297 -- Nom du capteur Interrupteur PushOn reboot +local devices_livebox_mac_adress = { -- MAC ADDRESS des périphériques à surveiller + "44:6D:6C:A2:68:0C", "8C:1A:BF:49:63:06", "00:25:22:6C:7B:8C", + "44:6D:57:8E:EA:E7", "C8:D0:83:09:22:D3" + } +local fichier_contacts = "/opt/domoticz/scripts/contacts.json" +json = assert(loadfile('/opt/domoticz/scripts/lua/JSON.lua'))() +commandArray = {} +-- SVP, ne rien changer sous cette ligne (sauf pour modifier le logging level) +function os.capture(cmd, raw) + local f = assert(io.popen(cmd, 'r')) + local s = assert(f:read('*a')) + f:close() + if raw then return s end + s = string.gsub(s, '^%s+', '') + s = string.gsub(s, '%s+$', '') + s = string.gsub(s, '[\n\r]+', ' ') + return s +end + +function disp_time(time) + local days = math.floor(time/86400) + local remaining = time % 86400 + local hours = math.floor(remaining/3600) + remaining = remaining % 3600 + local minutes = math.floor(remaining/60) + remaining = remaining % 60 + local seconds = remaining + return string.format("%d:%02d:%02d:%02d",days,hours,minutes,seconds) +end + +function traduction(str) -- supprime les accents de la chaîne str + if (str) then + str = string.gsub (str,"missed", "manqué") + str = string.gsub (str,"failed", "échoué") + str = string.gsub (str,"succeeded", "réussi") + end + return (str) +end +function format_date(str) -- supprime les caractères T et Z de la chaîne str et corrige l'heure a GMT +2 + if (str) then + _, _, A, M, j, h, m, s = string.find(str, "^(%d+)-(%d+)-(%d+)T(%d+):(%d+):(%d+)Z$") + h = h + 2 + str= A.."-"..M.."-"..j.." - "..h..":"..m..":"..s + end + return (str) +end +function ReverseTable(t) + local reversedTable = {} + local itemCount = #t + for k, v in ipairs(t) do + reversedTable[itemCount + 1 - k] = v + end + return reversedTable +end +function json2table(file) + local f = io.open(file, "rb") + if(f == nil) then + return "" + else + local content = f:read("*all") + f:close() + jsonValeur = json:decode(content) + return jsonValeur + end +end +function testActive(domoticz, name, active) + if active == true then + if domoticz.devices(name) then + domoticz.devices(name).switchOn().checkFirst() + end + domoticz.log("Activation de : " .. name, domoticz.LOG_INFO) + else + if domoticz.devices(name) then + domoticz.devices(name).switchOff().checkFirst() + end + domoticz.log("DésActivation de : " .. name, domoticz.LOG_INFO) + end +end + +contacts = {} +contacts = json2table(fichier_contacts) + +function searchName(contacts, phoneNumber) +-- for index, variable in pairs(contacts) do +-- if variable.Phone == phoneNumber then +-- name = variable.Name +-- end +-- end +-- if name == nil then + name = phoneNumber +-- end + return name +end +local scriptName = 'Livebox' +local scriptVersion = '1.7' + +local missedCallList = "" +local failedCallList = "" +local succeededCallList = "" +local patternMacAdresses = string.format("([^%s]+)", ";") + +return { + active = true, + logging = { + -- level = domoticz.LOG_DEBUG, -- Uncomment to override the dzVents global logging setting + -- level = domoticz.LOG_INFO, -- Seulement un niveau peut être actif; commenter les autres + -- level = domoticz.LOG_ERROR, + -- level = domoticz.LOG_DEBUG, + -- level = domoticz.LOG_MODULE_EXEC_INFO, + marker = scriptName..' '..scriptVersion + }, + on = { + timer = { + 'every '..tostring(fetchIntervalMins)..' minutes', + }, + devices = {wifi5,wifi24,clearCallList,reboot} + }, + + execute = function(domoticz, item) + --Connexion et récupération du cookies + os.execute("curl -s -o \""..myOutput.."\" -X POST -c \""..myCookies.."\" -H 'Content-Type: application/x-sah-ws-4-call+json' -H 'Authorization: X-Sah-Login' -d \"{\\\"service\\\":\\\"sah.Device.Information\\\",\\\"method\\\":\\\"createContext\\\",\\\"parameters\\\":{\\\"applicationName\\\":\\\"so_sdkut\\\",\\\"username\\\":\\\"admin\\\",\\\"password\\\":\\\""..password.."\\\"}}\" http://"..adresseLB.."/ws > /dev/null") + + --Lecture du cookies pour utilisation ultérieure + myContextID = os.capture("tail -n1 \""..myOutput.."\" | sed 's/{\"status\":0,\"data\":{\"contextID\":\"//1'| sed 's/\",//1' | sed 's/\"groups\":\"http,admin//1' | sed 's/\"}}//1'") + domoticz.log('Context : '..myContextID, domoticz.LOG_DEBUG) + + if (item.isTimer)then + --Envoi des commandes pour récupérer les informations + MIBs=os.capture("curl -s -b \""..myCookies.."\" -X POST -H 'Content-Type: application/x-sah-ws-4-call+json' -H \"X-Context: "..myContextID.."\" -d \"{\\\"service\\\":\\\"NeMo.Intf.data\\\",\\\"method\\\":\\\"getMIBs\\\",\\\"parameters\\\":{}}\" http://"..adresseLB.."/ws") + domoticz.log('MIBs : '..MIBs, domoticz.LOG_DEBUG) + + DSLstats=os.capture("curl -s -b \""..myCookies.."\" -X POST -H 'Content-Type: application/x-sah-ws-4-call+json' -H \"X-Context: "..myContextID.."\" -d \"{\\\"service\\\":\\\"NeMo.Intf.dsl0\\\",\\\"method\\\":\\\"getDSLStats\\\",\\\"parameters\\\":{}}\" http://"..adresseLB.."/ws") + domoticz.log('DSLstats : '..DSLstats, domoticz.LOG_DEBUG) + + WAN=os.capture("curl -s -b \""..myCookies.."\" -X POST -H 'Content-Type: application/x-sah-ws-4-call+json' -H \"X-Context: "..myContextID.."\" -d \"{\\\"service\\\":\\\"NMC\\\",\\\"method\\\":\\\"getWANStatus\\\",\\\"parameters\\\":{}}\" http://"..adresseLB.."/ws") + domoticz.log('WAN : '..WAN, domoticz.LOG_DEBUG) + + TVstatus=os.capture("curl -s -b \""..myCookies.."\" -X POST -H 'Content-Type: application/x-sah-ws-4-call+json' -H \"X-Context: "..myContextID.."\" -d \"{\\\"service\\\":\\\"NMC.OrangeTV\\\",\\\"method\\\":\\\"getIPTVStatus\\\",\\\"parameters\\\":{}}\" http://"..adresseLB.."/ws") + domoticz.log('TVstatus : '..TVstatus, domoticz.LOG_DEBUG) + + voip=os.capture("curl -s -b \""..myCookies.."\" -X POST -H 'Content-Type: application/x-sah-ws-4-call+json' -H \"X-Context: "..myContextID.."\" -d \"{\\\"service\\\":\\\"VoiceService.VoiceApplication\\\",\\\"method\\\":\\\"listTrunks\\\",\\\"parameters\\\":{}}\" http://"..adresseLB.."/ws") + domoticz.log('voip : '..voip, domoticz.LOG_DEBUG) + + devicesList=os.capture("curl -s -b \""..myCookies.."\" -X POST -H 'Content-Type: application/x-sah-ws-4-call+json' -H \"X-Context: "..myContextID.."\" -d \"{\\\"service\\\":\\\"Devices\\\",\\\"method\\\":\\\"get\\\",\\\"parameters\\\":{}}\" http://"..adresseLB.."/ws") + domoticz.log('devicesList : '..devicesList, domoticz.LOG_DEBUG) + + wifi=os.capture("curl -s -b \""..myCookies.."\" -X POST -H 'Content-Type: application/x-sah-ws-4-call+json' -H \"X-Context: "..myContextID.."\" -d \"{\\\"service\\\":\\\"NeMo.Intf.lan\\\",\\\"method\\\":\\\"getMIBs\\\",\\\"parameters\\\":{}}\" http://"..adresseLB.."/ws") + domoticz.log('wifi : '..wifi, domoticz.LOG_DEBUG) + + callList=os.capture("curl -s -b \""..myCookies.."\" -X POST -H 'Content-Type: application/x-sah-ws-4-call+json' -H \"X-Context: "..myContextID.."\" -d \"{\\\"service\\\":\\\"VoiceService.VoiceApplication\\\",\\\"method\\\":\\\"getCallList\\\",\\\"parameters\\\":{}}\" http://"..adresseLB.."/ws") + domoticz.log('callList : '..callList, domoticz.LOG_DEBUG) + + --Données de connexion + local lbAPIData = domoticz.utils.fromJSON(MIBs) + if lbAPIData.status == nil or lbAPIData == nil then + domoticz.log('Lecture de la MIBs impossible', domoticz.LOG_ERROR) + else + if SyncATM then domoticz.log('ATM Down: '..lbAPIData.status.dsl.dsl0.DownstreamCurrRate, domoticz.LOG_INFO) + domoticz.devices(SyncATM).updateCustomSensor(lbAPIData.status.dsl.dsl0.DownstreamCurrRate) end + + if SyncATMup then domoticz.log('ATM Up: '..lbAPIData.status.dsl.dsl0.UpstreamCurrRate, domoticz.LOG_INFO) + domoticz.devices(SyncATMup).updateCustomSensor(lbAPIData.status.dsl.dsl0.UpstreamCurrRate) end + + if Attn then domoticz.log('Attn : '..tostring(lbAPIData.status.dsl.dsl0.DownstreamLineAttenuation/10)..' dB', domoticz.LOG_INFO) + domoticz.devices(Attn).updateCustomSensor(tostring(lbAPIData.status.dsl.dsl0.DownstreamLineAttenuation/10)) end + + if MargedAttn then domoticz.log('Marge d\'Attn : '..tostring(lbAPIData.status.dsl.dsl0.DownstreamNoiseMargin/10)..' dB', domoticz.LOG_INFO) + domoticz.devices(MargedAttn).updateCustomSensor(tostring(lbAPIData.status.dsl.dsl0.DownstreamNoiseMargin/10)) end + + if UptimeLB then Uptime = disp_time(lbAPIData.status.dhcp.dhcp_data.Uptime) + domoticz.log('Uptime : '..Uptime, domoticz.LOG_INFO) + domoticz.devices(UptimeLB).updateText(Uptime) end + + domoticz.log('IP WAN : '..lbAPIData.status.dhcp.dhcp_data.IPAddress, domoticz.LOG_INFO) + if IPWAN and domoticz.devices(IPWAN).text ~= lbAPIData.status.dhcp.dhcp_data.IPAddress then + domoticz.devices(IPWAN).updateText(lbAPIData.status.dhcp.dhcp_data.IPAddress) + end + end + + -- Volume de données échangées + local lbAPIDataDSL = domoticz.utils.fromJSON(DSLstats) + if lbAPIDataDSL.status == nil then + domoticz.log('Lecture de la MIBs impossible', domoticz.LOG_ERROR) + else + if TransmitBlocks then domoticz.devices(TransmitBlocks).update(0,lbAPIDataDSL.status.TransmitBlocks) end + if ReceiveBlocks then domoticz.devices(ReceiveBlocks).update(0,lbAPIDataDSL.status.ReceiveBlocks) end + end + + -- Etat du lien WAN et IPv6 + local lbAPIDataInternet = domoticz.utils.fromJSON(WAN) + if lbAPIDataInternet.status == nil then + domoticz.log('Lecture de la MIBs impossible', domoticz.LOG_ERROR) + else + domoticz.log('Internet : '..lbAPIDataInternet.data.LinkState, domoticz.LOG_INFO) + if internet then + if (lbAPIDataInternet.data.LinkState == 'up' and domoticz.devices(internet).active == false)then + domoticz.devices(internet).switchOn() + elseif (lbAPIDataInternet.data.LinkState ~= 'up' and domoticz.devices(internet).active)then + domoticz.devices(internet).switchOff() + end + end + domoticz.log('IPv6 : '..lbAPIDataInternet.data.IPv6Address, domoticz.LOG_INFO) + if IPv6WAN and domoticz.devices(IPv6WAN).text ~= lbAPIDataInternet.data.IPv6Address then + domoticz.devices(IPv6WAN).updateText(lbAPIDataInternet.data.IPv6Address) + end + end + + -- État service VoIP + local lbAPIDataVoIP = domoticz.utils.fromJSON(voip) + if lbAPIDataVoIP.status == nil then + domoticz.log('Lecture de la MIBs impossible', domoticz.LOG_ERROR) + else + domoticz.log('VoIP : '..lbAPIDataVoIP.status[1].trunk_lines[1].status, domoticz.LOG_INFO) + if VoIP then + if (lbAPIDataVoIP.status[1].trunk_lines[1].status == 'Up' and domoticz.devices(VoIP).active == false)then + domoticz.devices(VoIP).switchOn() + elseif (lbAPIDataVoIP.status[1].trunk_lines[1].status ~= 'Up' and domoticz.devices(VoIP).active)then + domoticz.devices(VoIP).switchOff() + end + end + end + + --État service TV + local lbAPIDataTV = domoticz.utils.fromJSON(TVstatus) + if lbAPIDataTV.data == nil then + domoticz.log('Lecture de la MIBs impossible', domoticz.LOG_ERROR) + else + domoticz.log('TV : '..lbAPIDataTV.data.IPTVStatus, domoticz.LOG_INFO) + if ServiceTV then + if (lbAPIDataTV.data.IPTVStatus == 'Available' and domoticz.devices(ServiceTV).active == false)then + domoticz.devices(ServiceTV).switchOn() + elseif (lbAPIDataTV.data.IPTVStatus ~= 'Available' and domoticz.devices(ServiceTV).active)then + domoticz.devices(ServiceTV).switchOff() + end + end + end + + --État WiFi + local lbAPIDataWifi = domoticz.utils.fromJSON(wifi) + if lbAPIDataWifi.status == nil then + domoticz.log('Lecture de la MIBs impossible', domoticz.LOG_ERROR) + else + domoticz.log('Wifi 2.4 Ghz : '..lbAPIDataWifi.status.wlanvap.wl0.VAPStatus, domoticz.LOG_INFO) + if wifi24 then + if (lbAPIDataWifi.status.wlanvap.wl0.VAPStatus == 'Up' and domoticz.devices(wifi24).active == false)then + domoticz.devices(wifi24).switchOn() + elseif (lbAPIDataWifi.status.wlanvap.wl0.VAPStatus ~= 'Up' and domoticz.devices(wifi24).active)then + domoticz.devices(wifi24).switchOff() + end + end + + if wifi5 then + domoticz.log('Wifi 5 Ghz : '..lbAPIDataWifi.status.wlanvap.eth6.VAPStatus, domoticz.LOG_INFO) + if (lbAPIDataWifi.status.wlanvap.eth6.VAPStatus == 'Up' and domoticz.devices(wifi5).active == false)then + domoticz.devices(wifi5).update(1,0) + elseif (lbAPIDataWifi.status.wlanvap.eth6.VAPStatus ~= 'Up' and domoticz.devices(wifi5).active)then + domoticz.devices(wifi5).update(0,0) + end + end + end + + --Dernier Appel reçu ou émis + local lbAPIDataCallList = domoticz.utils.fromJSON(callList) + if lbAPIDataCallList.status == nil then + domoticz.log('Lecture de la MIBs impossible', domoticz.LOG_ERROR) + else + domoticz.log('CallList : '..#lbAPIDataCallList.status, domoticz.LOG_INFO) + if (#lbAPIDataCallList.status>0) then + domoticz.log('Dernier Appel : '..lbAPIDataCallList.status[#lbAPIDataCallList.status].remoteNumber, domoticz.LOG_INFO) + domoticz.log('Dernier Appel : '..traduction(lbAPIDataCallList.status[#lbAPIDataCallList.status].callType), domoticz.LOG_INFO) + NumeroEtat = searchName(contacts, lbAPIDataCallList.status[#lbAPIDataCallList.status].remoteNumber) .. " - "..lbAPIDataCallList.status[#lbAPIDataCallList.status].callType + if DernierAppel and domoticz.devices(DernierAppel).text ~= traduction(NumeroEtat) then + domoticz.devices(DernierAppel).updateText(traduction(NumeroEtat)) + end + -- x Appels manqués, sans réponse, réussis + for i, call in ipairs(ReverseTable(lbAPIDataCallList.status)) do + if call.callType == "missed" and nbMissedCall > 0 then + domoticz.log(call.remoteNumber .. " " .. traduction(call.callType) .. " " .. format_date(call.startTime), domoticz.LOG_INFO) + missedCallList = missedCallList .. searchName(contacts, call.remoteNumber) .. " - " .. format_date(call.startTime) .. "\n" + nbMissedCall = nbMissedCall - 1 + end + if call.callType == "failed" and nbFailedCall > 0 then + domoticz.log(call.remoteNumber .. " " .. traduction(call.callType) .." ".. format_date(call.startTime), domoticz.LOG_INFO) + failedCallList = failedCallList .. searchName(contacts, call.remoteNumber) .." - ".. format_date(call.startTime) .. "\n" + nbFailedCall = nbFailedCall - 1 + end + if call.callType == "succeeded" and nbSucceededCall > 0 then + domoticz.log(call.remoteNumber .. " " .. traduction(call.callType) .. " " .. format_date(call.startTime), domoticz.LOG_INFO) + succeededCallList = succeededCallList .. searchName(contacts, call.remoteNumber) .. " - " .. format_date(call.startTime) .. "\n" + nbSucceededCall = nbSucceededCall - 1 + end + end + if missedCallList == "" then missedCallList = "Aucun appel à afficher" end + domoticz.log('Appels manqués : \n'..missedCallList, domoticz.LOG_INFO) + if missedCall and domoticz.devices(missedCall).text ~= traduction(missedCallList) then + domoticz.devices(missedCall).updateText(traduction(missedCallList)) + end + if failedCallList == "" then failedCallList = "Aucun appel à afficher" end + domoticz.log('Appels sans réponse : \n'..failedCallList, domoticz.LOG_INFO) + if failedCall and domoticz.devices(failedCall).text ~= traduction(failedCallList) then + domoticz.devices(failedCall).updateText(traduction(failedCallList)) + end + if succeededCallList == "" then succeededCallList = "Aucun appel à afficher" end + domoticz.log('Appels réussis : \n'..succeededCallList, domoticz.LOG_INFO) + if succeededCall and domoticz.devices(succeededCall).text ~= traduction(succeededCallList) then + domoticz.devices(succeededCall).updateText(traduction(succeededCallList)) + end + else + NumeroEtat = "Aucun appel à afficher" + domoticz.log('Dernier Appel : '..NumeroEtat, domoticz.LOG_INFO) + if DernierAppel and domoticz.devices(DernierAppel).text ~= NumeroEtat then + domoticz.devices(DernierAppel).updateText(NumeroEtat) + end + if missedCallList == "" then missedCallList = "Aucun appel à afficher" end + domoticz.log('Appels manqués : \n'..missedCallList, domoticz.LOG_INFO) + if missedCall and domoticz.devices(missedCall).text ~= traduction(missedCallList) then + domoticz.devices(missedCall).updateText(traduction(missedCallList)) + end + if failedCallList == "" then failedCallList = "Aucun appel à afficher" end + domoticz.log('Appels sans réponse : \n'..failedCallList, domoticz.LOG_INFO) + if failedCall and domoticz.devices(failedCall).text ~= traduction(failedCallList) then + domoticz.devices(failedCall).updateText(traduction(failedCallList)) + end + if succeededCallList == "" then succeededCallList = "Aucun appel à afficher" end + domoticz.log('Appels réussis : \n'..succeededCallList, domoticz.LOG_INFO) + if succeededCall and domoticz.devices(succeededCall).text ~= traduction(succeededCallList) then + domoticz.devices(succeededCall).updateText(traduction(succeededCallList)) + end + end + end + + local json_peripheriques = domoticz.utils.fromJSON(devicesList) + etatPeripheriques = false + -- Liste des périphériques + + for index, peripherique in pairs(json_peripheriques.status) do + domoticz.log("Péripherique " .. index .. " ".. peripherique.Name .." " .. tostring(peripherique.IPAddress) .. " [".. tostring(peripherique.PhysAddress) .."] actif : ".. tostring(peripherique.Active), domoticz.LOG_DEBUG) + for i, mac in pairs(devices_livebox_mac_adress) do + -- mac = string.lower(mac) + if peripherique.PhysAddress == mac then + domoticz.log("Statut du périphérique ".. peripherique.Name .." [" .. mac .. "] => actif:" .. tostring(peripherique.Active), domoticz.LOG_INFO) + if peripherique.Active == true then + etatPeripheriques = true + if domoticz.devices(peripherique.Name) then + domoticz.devices(peripherique.Name).switchOn().checkFirst() + end + domoticz.log("Activation de : " .. peripherique.Name, domoticz.LOG_INFO) + else + if domoticz.devices(peripherique.Name) then + domoticz.devices(peripherique.Name).switchOff().checkFirst() + end + domoticz.log("DésActivation de : " .. peripherique.Name, domoticz.LOG_INFO) + end + end + end + + local name = peripherique.Name + local active = peripherique.Active + --debug("Name : "..name.." "..tostring(active)) + + if (name == "Theo") then + --commandArray['Theo']='On' + testActive(domoticz, 'Theo', active) + end + if (name == "iPhone-de-Jerome") then + --commandArray['moi']='On' + testActive(domoticz, "Moi", active) + end + if (name == "Akhenaton-3") then + testActive(domoticz, "Akhenaton", active) + end + if (name == "Manon") then + --commandArray['Manon']='On' + testActive(domoticz, "Manon", active) + end + if (name == "DomiPro") then + --commandArray['Manon']='On' + testActive(domoticz, "Domi", active) + end + if (name == "octoprint-1") then + testActive(domoticz, "Octoprint", active) + end + if (name == "orangepizero-1") then + testActive(domoticz, "orangepizero", active) + end + if (name == "TeleChambre" + or name == "Volumio" or name == "LibreELEC" or name == "Akhesa" + or name == "SoutiHP" or name == "Hackintosh" + or name == "Recovery") then + testActive(domoticz, name, active) + end + + if (name == "RadiateurManon" or name == "RadiateurTheo" or name == "RadiateurBureau" + or name == "RadiateurChambre") then + if active then + -- nothing + else + -- commandArray['SendNotification']='Alerte radiateur '..name..'#Alerte radiateur ne repond pas au ping '..name + end + end + end + else + if(item.name == wifi5)then + os.execute("curl -s -b \""..myCookies.."\" -X POST -H 'Content-Type: application/x-sah-ws-4-call+json' -H \"X-Context: ".. + myContextID.."\" -d \"{\\\"service\\\":\\\"NeMo.Intf.lan\\\",\\\"method\\\":\\\"setWLANConfig\\\",\\\"parameters\\\":{\\\"mibs\\\":{\\\"penable\\\":{\\\"wifi0_quan\\\":{\\\"PersistentEnable\\\":".. + tostring(item.active)..", \\\"Enable\\\":true}}}}}\" http://"..adresseLB.."/ws &") + domoticz.log("wifi5 "..tostring(item.active),domoticz.LOG_INFO) + elseif(item.name == wifi24)then + os.execute("curl -s -b \""..myCookies.."\" -X POST -H 'Content-Type: application/x-sah-ws-4-call+json' -H \"X-Context: ".. + myContextID.."\" -d \"{\\\"service\\\":\\\"NeMo.Intf.lan\\\",\\\"method\\\":\\\"setWLANConfig\\\",\\\"parameters\\\":{\\\"mibs\\\":{\\\"penable\\\":{\\\"wifi0_bcm\\\":{\\\"PersistentEnable\\\":".. + tostring(item.active)..", \\\"Enable\\\":true}}}}}\" http://"..adresseLB.."/ws &") + domoticz.log("wifi24 "..tostring(item.active),domoticz.LOG_INFO) + elseif(item.name == clearCallList)then + os.execute("curl -s -b \""..myCookies.."\" -X POST -H 'Content-Type: application/x-sah-ws-4-call+json' -H \"X-Context: ".. + myContextID.."\" -d \"{\\\"service\\\":\\\"VoiceService.VoiceApplication\\\",\\\"method\\\":\\\"clearCallList\\\",\\\"parameters\\\":{}}\" http://"..adresseLB.."/ws &") + domoticz.log("clearCallList "..tostring(item.active),domoticz.LOG_INFO) + + elseif(item.name == reboot)then + os.execute("curl -s -b \""..myCookies.."\" -X POST -H 'Content-Type: application/x-sah-ws-4-call+json' -H \"X-Context: ".. + myContextID.."\" -d \"{\\\"parameters\\\":{}}\" http://"..adresseLB.."/sysbus/NMC:reboot &") + domoticz.log("reboot "..tostring(item.active),domoticz.LOG_INFO) + end + end + --Déconnexion et suppression des fichiers temporaires + os.execute("curl -s -b "..myCookies.." -X POST http://"..adresseLB.."/logout &") + -- os.execute('rm "'..myCookies..'" "'..myOutput..'" &') + end +} + diff --git a/enedis.sh b/enedis.sh new file mode 100755 index 0000000..effb757 --- /dev/null +++ b/enedis.sh @@ -0,0 +1,18 @@ +#!/bin/bash +export PATH=/opt/domoticz/:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin + +# Récupérer la date actuelle au format YYYY-MM-DD +current_date=$(date +%F) + +# Calculer la date antérieure de 30 jours +previous_date=$(date -d "$current_date - 30 days" +%F) +previous_date_1=$(date -d "$current_date - 1 days" +%F) + +echo "Date actuelle : $current_date" +echo "Date antérieure de 30 jours : $previous_date" + + +/usr/bin/curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOlsiMTQ4OTg1NTI3OTMzOTciXSwiZXhwIjoxNzk1NTQ3MjgxLCJpYXQiOjE3MDExOTg0ODF9.l1kWoiJLFXsN9YUAaxn7Sy0PvtFiFt5spjF1E_deu_E" -X GET "https://conso.boris.sh/api/daily_consumption?prm=14898552793397&start=$previous_date&end=$current_date" >/opt/domoticz/www/enedis.json + +/usr/bin/curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOlsiMTQ4OTg1NTI3OTMzOTciXSwiZXhwIjoxNzk1NTQ3MjgxLCJpYXQiOjE3MDExOTg0ODF9.l1kWoiJLFXsN9YUAaxn7Sy0PvtFiFt5spjF1E_deu_E" -X GET "https://conso.boris.sh/api/consumption_load_curve?prm=14898552793397&start=$previous_date_1&end=$current_date" >/opt/domoticz/www/enedis_curve.json + diff --git a/etcSAVE/init.d/mplayerd b/etcSAVE/init.d/mplayerd new file mode 100755 index 0000000..5434e46 --- /dev/null +++ b/etcSAVE/init.d/mplayerd @@ -0,0 +1,77 @@ +# /etc/init.d/mplayerd +### BEGIN INIT INFO +# Provides: mplayer +# Required-Start: $network $syslog +# Required-Stop: $network $syslog +# Should-Start: $time +# Should-Stop: $time +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start and stop the mplayer daemon +# Description: mplayer daemon +### END INIT INFO + +CONTROLFILE="/tmp/mplayercontrol" +DAEMONUSER=pi + +DAEMON=/usr/bin/mplayer +#DAEMON_ARGS="-slave -idle -input file=$CONTROLFILE" +DAEMON_ARGS="-slave -idle -ao alsa -playlist http://volumio:8000/mpd.m3u" +PIDFILE=/tmp/mplayerd.pid + +start() { + echo "Starting mplayer..." + + # Prepare fifo file + rm -rf $CONTROLFILE + mkfifo $CONTROLFILE + chmod a+rw $CONTROLFILE + + start-stop-daemon --start --quiet --user $DAEMONUSER \ + --make-pidfile --pidfile $PIDFILE --background \ + --exec /bin/bash -- -c "HOME=/home/$DAEMONUSER $DAEMON $DAEMON_ARGS > /tmp/mplayerd.log 2>&1" + + echo "Started for user: $DAEMONUSER." +} + +stop() { + echo "Stopping mplayer..." + killall mplayer + kill -9 `cat $PIDFILE` + # Cleanup fifo file + rm -rf $CONTROLFILE +} + +status() { + if [ -z `cat $PIDFILE` ]; + then + echo "mplayerd: not running." + else + echo "mplayerd: running." + fi +} + + +case "$1" in + start) + start + ;; + + stop) + stop + ;; + + restart|reload|force-reload) + stop + start + ;; + + status) + status + ;; + + *) + echo "Usage: /etc/init.d/mplayerd {start|stop|reload|force-reload|restart|status}" + exit 1 + +esac diff --git a/etcSAVE/motion/motion.conf b/etcSAVE/motion/motion.conf new file mode 100755 index 0000000..60dd89c --- /dev/null +++ b/etcSAVE/motion/motion.conf @@ -0,0 +1,639 @@ +# Rename this distribution example file to motion.conf +# +# This config file was generated by motion 3.2.12 + + +############################################################ +# Daemon +############################################################ + +# Start in daemon (background) mode and release terminal (default: off) +daemon off + +# File to store the process ID, also called pid file. (default: not defined) +process_id_file /home/pi/motion/motion.pid + +############################################################ +# Basic Setup Mode +############################################################ + +# Start in Setup-Mode, daemon disabled. (default: off) +setup_mode off + +########################################################### +# Capture device options +############################################################ + +# Videodevice to be used for capturing (default /dev/video0) +# for FreeBSD default is /dev/bktr0 +videodevice /dev/video0 + +# v4l2_palette allows to choose preferable palette to be use by motion +# to capture from those supported by your videodevice. (default: 8) +# E.g. if your videodevice supports both V4L2_PIX_FMT_SBGGR8 and +# V4L2_PIX_FMT_MJPEG then motion will by default use V4L2_PIX_FMT_MJPEG. +# Setting v4l2_palette to 1 forces motion to use V4L2_PIX_FMT_SBGGR8 +# instead. +# +# Values : +# V4L2_PIX_FMT_SN9C10X : 0 'S910' +# V4L2_PIX_FMT_SBGGR8 : 1 'BA81' +# V4L2_PIX_FMT_MJPEG : 2 'MJPEG' +# V4L2_PIX_FMT_JPEG : 3 'JPEG' +# V4L2_PIX_FMT_RGB24 : 4 'RGB3' +# V4L2_PIX_FMT_UYVY : 5 'UYVY' +# V4L2_PIX_FMT_YUYV : 6 'YUYV' +# V4L2_PIX_FMT_YUV422P : 7 '422P' +# V4L2_PIX_FMT_YUV420 : 8 'YU12' +v4l2_palette 8 + +# Tuner device to be used for capturing using tuner as source (default /dev/tuner0) +# This is ONLY used for FreeBSD. Leave it commented out for Linux +; tunerdevice /dev/tuner0 + +# The video input to be used (default: 8) +# Should normally be set to 0 or 1 for video/TV cards, and 8 for USB cameras +input 8 + +# The video norm to use (only for video capture and TV tuner cards) +# Values: 0 (PAL), 1 (NTSC), 2 (SECAM), 3 (PAL NC no colour). Default: 0 (PAL) +norm 0 + +# The frequency to set the tuner to (kHz) (only for TV tuner cards) (default: 0) +frequency 0 + +# Rotate image this number of degrees. The rotation affects all saved images as +# well as mpeg movies. Valid values: 0 (default = no rotation), 90, 180 and 270. +rotate 0 + +# Image width (pixels). Valid range: Camera dependent, default: 352 +width 640 + +# Image height (pixels). Valid range: Camera dependent, default: 288 +height 480 + +# Maximum number of frames to be captured per second. +# Valid range: 2-100. Default: 100 (almost no limit). +framerate 2 + +# Minimum time in seconds between capturing picture frames from the camera. +# Default: 0 = disabled - the capture rate is given by the camera framerate. +# This option is used when you want to capture images at a rate lower than 2 per second. +minimum_frame_time 0 + +# URL to use if you are using a network camera, size will be autodetected (incl http:// ftp:// or file:///) +# Must be a URL that returns single jpeg pictures or a raw mjpeg stream. Default: Not defined +; netcam_url value + +# Username and password for network camera (only if required). Default: not defined +# Syntax is user:password +; netcam_userpass value + +# The setting for keep-alive of network socket, should improve performance on compatible net cameras. +# 1.0: The historical implementation using HTTP/1.0, closing the socket after each http request. +# keep_alive: Use HTTP/1.0 requests with keep alive header to reuse the same connection. +# 1.1: Use HTTP/1.1 requests that support keep alive as default. +# Default: 1.0 +; netcam_http 1.0 + +# URL to use for a netcam proxy server, if required, e.g. "http://myproxy". +# If a port number other than 80 is needed, use "http://myproxy:1234". +# Default: not defined +; netcam_proxy value + +# Set less strict jpeg checks for network cameras with a poor/buggy firmware. +# Default: off +netcam_tolerant_check off + +# Let motion regulate the brightness of a video device (default: off). +# The auto_brightness feature uses the brightness option as its target value. +# If brightness is zero auto_brightness will adjust to average brightness value 128. +# Only recommended for cameras without auto brightness +auto_brightness off + +# Set the initial brightness of a video device. +# If auto_brightness is enabled, this value defines the average brightness level +# which Motion will try and adjust to. +# Valid range 0-255, default 0 = disabled +brightness 0 + +# Set the contrast of a video device. +# Valid range 0-255, default 0 = disabled +contrast 0 + +# Set the saturation of a video device. +# Valid range 0-255, default 0 = disabled +saturation 0 + +# Set the hue of a video device (NTSC feature). +# Valid range 0-255, default 0 = disabled +hue 0 + + +############################################################ +# Round Robin (multiple inputs on same video device name) +############################################################ + +# Number of frames to capture in each roundrobin step (default: 1) +roundrobin_frames 1 + +# Number of frames to skip before each roundrobin step (default: 1) +roundrobin_skip 1 + +# Try to filter out noise generated by roundrobin (default: off) +switchfilter off + + +############################################################ +# Motion Detection Settings: +############################################################ + +# Threshold for number of changed pixels in an image that +# triggers motion detection (default: 1500) +threshold 1500 + +# Automatically tune the threshold down if possible (default: off) +threshold_tune off + +# Noise threshold for the motion detection (default: 32) +noise_level 32 + +# Automatically tune the noise threshold (default: on) +noise_tune on + +# Despeckle motion image using (e)rode or (d)ilate or (l)abel (Default: not defined) +# Recommended value is EedDl. Any combination (and number of) of E, e, d, and D is valid. +# (l)abeling must only be used once and the 'l' must be the last letter. +# Comment out to disable +despeckle EedDl + +# Detect motion in predefined areas (1 - 9). Areas are numbered like that: 1 2 3 +# A script (on_area_detected) is started immediately when motion is 4 5 6 +# detected in one of the given areas, but only once during an event. 7 8 9 +# One or more areas can be specified with this option. (Default: not defined) +; area_detect value + +# PGM file to use as a sensitivity mask. +# Full path name to. (Default: not defined) +; mask_file value + +# Dynamically create a mask file during operation (default: 0) +# Adjust speed of mask changes from 0 (off) to 10 (fast) +smart_mask_speed 0 + +# Ignore sudden massive light intensity changes given as a percentage of the picture +# area that changed intensity. Valid range: 0 - 100 , default: 0 = disabled +lightswitch 0 + +# Picture frames must contain motion at least the specified number of frames +# in a row before they are detected as true motion. At the default of 1, all +# motion is detected. Valid range: 1 to thousands, recommended 1-5 +minimum_motion_frames 1 + +# Specifies the number of pre-captured (buffered) pictures from before motion +# was detected that will be output at motion detection. +# Recommended range: 0 to 5 (default: 0) +# Do not use large values! Large values will cause Motion to skip video frames and +# cause unsmooth mpegs. To smooth mpegs use larger values of post_capture instead. +pre_capture 0 + +# Number of frames to capture after motion is no longer detected (default: 0) +post_capture 0 + +# Gap is the seconds of no motion detection that triggers the end of an event +# An event is defined as a series of motion images taken within a short timeframe. +# Recommended value is 60 seconds (Default). The value 0 is allowed and disables +# events causing all Motion to be written to one single mpeg file and no pre_capture. +gap 60 + +# Maximum length in seconds of an mpeg movie +# When value is exceeded a new mpeg file is created. (Default: 0 = infinite) +max_mpeg_time 0 + +# Always save images even if there was no motion (default: off) +output_all off + + +############################################################ +# Image File Output +############################################################ + +# Output 'normal' pictures when motion is detected (default: on) +# Valid values: on, off, first, best, center +# When set to 'first', only the first picture of an event is saved. +# Picture with most motion of an event is saved when set to 'best'. +# Picture with motion nearest center of picture is saved when set to 'center'. +# Can be used as preview shot for the corresponding movie. +output_normal off + +# Output pictures with only the pixels moving object (ghost images) (default: off) +output_motion off + +# The quality (in percent) to be used by the jpeg compression (default: 75) +quality 75 + +# Output ppm images instead of jpeg (default: off) +ppm off + + +############################################################ +# FFMPEG related options +# Film (mpeg) file output, and deinterlacing of the video input +# The options movie_filename and timelapse_filename are also used +# by the ffmpeg feature +############################################################ + +# Use ffmpeg to encode mpeg movies in realtime (default: off) +ffmpeg_cap_new on + +# Use ffmpeg to make movies with only the pixels moving +# object (ghost images) (default: off) +ffmpeg_cap_motion off + +# Use ffmpeg to encode a timelapse movie +# Default value 0 = off - else save frame every Nth second +ffmpeg_timelapse 0 + +# The file rollover mode of the timelapse video +# Valid values: hourly, daily (default), weekly-sunday, weekly-monday, monthly, manual +ffmpeg_timelapse_mode daily + +# Bitrate to be used by the ffmpeg encoder (default: 400000) +# This option is ignored if ffmpeg_variable_bitrate is not 0 (disabled) +ffmpeg_bps 500000 + +# Enables and defines variable bitrate for the ffmpeg encoder. +# ffmpeg_bps is ignored if variable bitrate is enabled. +# Valid values: 0 (default) = fixed bitrate defined by ffmpeg_bps, +# or the range 2 - 31 where 2 means best quality and 31 is worst. +ffmpeg_variable_bitrate 0 + +# Codec to used by ffmpeg for the video compression. +# Timelapse mpegs are always made in mpeg1 format independent from this option. +# Supported formats are: mpeg1 (ffmpeg-0.4.8 only), mpeg4 (default), and msmpeg4. +# mpeg1 - gives you files with extension .mpg +# mpeg4 or msmpeg4 - gives you files with extension .avi +# msmpeg4 is recommended for use with Windows Media Player because +# it requires no installation of codec on the Windows client. +# swf - gives you a flash film with extension .swf +# flv - gives you a flash video with extension .flv +# ffv1 - FF video codec 1 for Lossless Encoding ( experimental ) +# mov - QuickTime ( testing ) +ffmpeg_video_codec mpeg4 + +# Use ffmpeg to deinterlace video. Necessary if you use an analog camera +# and see horizontal combing on moving objects in video or pictures. +# (default: off) +ffmpeg_deinterlace off + + +############################################################ +# Snapshots (Traditional Periodic Webcam File Output) +############################################################ + +# Make automated snapshot every N seconds (default: 0 = disabled) +snapshot_interval 0 + + +############################################################ +# Text Display +# %Y = year, %m = month, %d = date, +# %H = hour, %M = minute, %S = second, %T = HH:MM:SS, +# %v = event, %q = frame number, %t = thread (camera) number, +# %D = changed pixels, %N = noise level, \n = new line, +# %i and %J = width and height of motion area, +# %K and %L = X and Y coordinates of motion center +# %C = value defined by text_event - do not use with text_event! +# You can put quotation marks around the text to allow +# leading spaces +############################################################ + +# Locate and draw a box around the moving object. +# Valid values: on, off and preview (default: off) +# Set to 'preview' will only draw a box in preview_shot pictures. +locate off + +# Draws the timestamp using same options as C function strftime(3) +# Default: %Y-%m-%d\n%T = date in ISO format and time in 24 hour clock +# Text is placed in lower right corner +text_right %Y-%m-%d\n%T-%q + +# Draw a user defined text on the images using same options as C function strftime(3) +# Default: Not defined = no text +# Text is placed in lower left corner +; text_left CAMERA %t + +# Draw the number of changed pixed on the images (default: off) +# Will normally be set to off except when you setup and adjust the motion settings +# Text is placed in upper right corner +text_changes on + +# This option defines the value of the special event conversion specifier %C +# You can use any conversion specifier in this option except %C. Date and time +# values are from the timestamp of the first image in the current event. +# Default: %Y%m%d%H%M%S +# The idea is that %C can be used filenames and text_left/right for creating +# a unique identifier for each event. +text_event %Y%m%d%H%M%S + +# Draw characters at twice normal size on images. (default: off) +text_double on + + +############################################################ +# Target Directories and filenames For Images And Films +# For the options snapshot_, jpeg_, mpeg_ and timelapse_filename +# you can use conversion specifiers +# %Y = year, %m = month, %d = date, +# %H = hour, %M = minute, %S = second, +# %v = event, %q = frame number, %t = thread (camera) number, +# %D = changed pixels, %N = noise level, +# %i and %J = width and height of motion area, +# %K and %L = X and Y coordinates of motion center +# %C = value defined by text_event +# Quotation marks round string are allowed. +############################################################ + +# Target base directory for pictures and films +# Recommended to use absolute path. (Default: current working directory) +target_dir /home/pi/motion/ + +# File path for snapshots (jpeg or ppm) relative to target_dir +# Default: %v-%Y%m%d%H%M%S-snapshot +# Default value is equivalent to legacy oldlayout option +# For Motion 3.0 compatible mode choose: %Y/%m/%d/%H/%M/%S-snapshot +# File extension .jpg or .ppm is automatically added so do not include this. +# Note: A symbolic link called lastsnap.jpg created in the target_dir will always +# point to the latest snapshot, unless snapshot_filename is exactly 'lastsnap' +snapshot_filename %v-%Y%m%d%H%M%S-snapshot + +# File path for motion triggered images (jpeg or ppm) relative to target_dir +# Default: %v-%Y%m%d%H%M%S-%q +# Default value is equivalent to legacy oldlayout option +# For Motion 3.0 compatible mode choose: %Y/%m/%d/%H/%M/%S-%q +# File extension .jpg or .ppm is automatically added so do not include this +# Set to 'preview' together with best-preview feature enables special naming +# convention for preview shots. See motion guide for details +jpeg_filename %v-%Y%m%d%H%M%S-%q + +# File path for motion triggered ffmpeg films (mpeg) relative to target_dir +# Default: %v-%Y%m%d%H%M%S +# Default value is equivalent to legacy oldlayout option +# For Motion 3.0 compatible mode choose: %Y/%m/%d/%H%M%S +# File extension .mpg or .avi is automatically added so do not include this +# This option was previously called ffmpeg_filename +movie_filename %v-%Y%m%d%H%M%S + +# File path for timelapse mpegs relative to target_dir +# Default: %Y%m%d-timelapse +# Default value is near equivalent to legacy oldlayout option +# For Motion 3.0 compatible mode choose: %Y/%m/%d-timelapse +# File extension .mpg is automatically added so do not include this +timelapse_filename %Y%m%d-timelapse + + +############################################################ +# Live Webcam Server +############################################################ + +# The mini-http server listens to this port for requests (default: 0 = disabled) +webcam_port 8082 + +# Quality of the jpeg (in percent) images produced (default: 50) +webcam_quality 50 + +# Output frames at 1 fps when no motion is detected and increase to the +# rate given by webcam_maxrate when motion is detected (default: off) +webcam_motion on + +# Maximum framerate for webcam streams (default: 1) +webcam_maxrate 5 + +# Restrict webcam connections to localhost only (default: on) +webcam_localhost off + +# Limits the number of images per connection (default: 0 = unlimited) +# Number can be defined by multiplying actual webcam rate by desired number of seconds +# Actual webcam rate is the smallest of the numbers framerate and webcam_maxrate +webcam_limit 0 + + +############################################################ +# HTTP Based Control +############################################################ + +# TCP/IP port for the http server to listen on (default: 0 = disabled) +control_port 8080 + +# Restrict control connections to localhost only (default: on) +control_localhost on + +# Output for http server, select off to choose raw text plain (default: on) +control_html_output on + +# Authentication for the http based control. Syntax username:password +# Default: not defined (Disabled) +; control_authentication username:password + + +############################################################ +# Tracking (Pan/Tilt) +############################################################ + +# Type of tracker (0=none (default), 1=stepper, 2=iomojo, 3=pwc, 4=generic, 5=uvcvideo) +# The generic type enables the definition of motion center and motion size to +# be used with the conversion specifiers for options like on_motion_detected +track_type 0 + +# Enable auto tracking (default: off) +track_auto off + +# Serial port of motor (default: none) +; track_port value + +# Motor number for x-axis (default: 0) +track_motorx 0 + +# Motor number for y-axis (default: 0) +track_motory 0 + +# Maximum value on x-axis (default: 0) +track_maxx 0 + +# Maximum value on y-axis (default: 0) +track_maxy 0 + +# ID of an iomojo camera if used (default: 0) +track_iomojo_id 0 + +# Angle in degrees the camera moves per step on the X-axis +# with auto-track (default: 10) +# Currently only used with pwc type cameras +track_step_angle_x 10 + +# Angle in degrees the camera moves per step on the Y-axis +# with auto-track (default: 10) +# Currently only used with pwc type cameras +track_step_angle_y 10 + +# Delay to wait for after tracking movement as number +# of picture frames (default: 10) +track_move_wait 10 + +# Speed to set the motor to (stepper motor option) (default: 255) +track_speed 255 + +# Number of steps to make (stepper motor option) (default: 40) +track_stepsize 40 + + +############################################################ +# External Commands, Warnings and Logging: +# You can use conversion specifiers for the on_xxxx commands +# %Y = year, %m = month, %d = date, +# %H = hour, %M = minute, %S = second, +# %v = event, %q = frame number, %t = thread (camera) number, +# %D = changed pixels, %N = noise level, +# %i and %J = width and height of motion area, +# %K and %L = X and Y coordinates of motion center +# %C = value defined by text_event +# %f = filename with full path +# %n = number indicating filetype +# Both %f and %n are only defined for on_picture_save, +# on_movie_start and on_movie_end +# Quotation marks round string are allowed. +############################################################ + +# Do not sound beeps when detecting motion (default: on) +# Note: Motion never beeps when running in daemon mode. +quiet on + +# Command to be executed when an event starts. (default: none) +# An event starts at first motion detected after a period of no motion defined by gap +; on_event_start value +on_event_start /opt/domoticz/scripts/on_event_start.sh + +# Command to be executed when an event ends after a period of no motion +# (default: none). The period of no motion is defined by option gap. +; on_event_end value +on_event_end /opt/domoticz/scripts/on_event_end.sh + +# Command to be executed when a picture (.ppm|.jpg) is saved (default: none) +# To give the filename as an argument to a command append it with %f +; on_picture_save value + +# Command to be executed when a motion frame is detected (default: none) +on_motion_detected /opt/domoticz/scripts/on_motion_detected.sh + +# Command to be executed when motion in a predefined area is detected +# Check option 'area_detect'. (default: none) +; on_area_detected value + +# Command to be executed when a movie file (.mpg|.avi) is created. (default: none) +# To give the filename as an argument to a command append it with %f +; on_movie_start value + +# Command to be executed when a movie file (.mpg|.avi) is closed. (default: none) +# To give the filename as an argument to a command append it with %f +; on_movie_end value + +# Command to be executed when a camera can't be opened or if it is lost +# NOTE: There is situations when motion doesn't detect a lost camera! +# It depends on the driver, some drivers don't detect a lost camera at all +# Some hang the motion thread. Some even hang the PC! (default: none) +; on_camera_lost value + +############################################################ +# Common Options For MySQL and PostgreSQL database features. +# Options require the MySQL/PostgreSQL options to be active also. +############################################################ + +# Log to the database when creating motion triggered image file (default: on) +sql_log_image on + +# Log to the database when creating a snapshot image file (default: on) +sql_log_snapshot on + +# Log to the database when creating motion triggered mpeg file (default: off) +sql_log_mpeg off + +# Log to the database when creating timelapse mpeg file (default: off) +sql_log_timelapse off + +# SQL query string that is sent to the database +# Use same conversion specifiers has for text features +# Additional special conversion specifiers are +# %n = the number representing the file_type +# %f = filename with full path +# Default value: +# insert into security(camera, filename, frame, file_type, time_stamp, text_event) values('%t', '%f', '%q', '%n', '%Y-%m-%d %T', '%C') +sql_query insert into security(camera, filename, frame, file_type, time_stamp, event_time_stamp) values('%t', '%f', '%q', '%n', '%Y-%m-%d %T', '%C') + + +############################################################ +# Database Options For MySQL +############################################################ + +# Mysql database to log to (default: not defined) +; mysql_db value + +# The host on which the database is located (default: localhost) +; mysql_host value + +# User account name for MySQL database (default: not defined) +; mysql_user value + +# User password for MySQL database (default: not defined) +; mysql_password value + + +############################################################ +# Database Options For PostgreSQL +############################################################ + +# PostgreSQL database to log to (default: not defined) +; pgsql_db value + +# The host on which the database is located (default: localhost) +; pgsql_host value + +# User account name for PostgreSQL database (default: not defined) +; pgsql_user value + +# User password for PostgreSQL database (default: not defined) +; pgsql_password value + +# Port on which the PostgreSQL database is located (default: 5432) +; pgsql_port 5432 + + +############################################################ +# Video Loopback Device (vloopback project) +############################################################ + +# Output images to a video4linux loopback device +# The value '-' means next available (default: not defined) +; video_pipe value + +# Output motion images to a video4linux loopback device +# The value '-' means next available (default: not defined) +; motion_video_pipe value + + +############################################################## +# Thread config files - One for each camera. +# Except if only one camera - You only need this config file. +# If you have more than one camera you MUST define one thread +# config file for each camera in addition to this config file. +############################################################## + +# Remember: If you have more than one camera you must have one +# thread file for each camera. E.g. 2 cameras requires 3 files: +# This motion.conf file AND thread1.conf and thread2.conf. +# Only put the options that are unique to each camera in the +# thread config files. +; thread /usr/local/etc/thread1.conf +; thread /usr/local/etc/thread2.conf +; thread /usr/local/etc/thread3.conf +; thread /usr/local/etc/thread4.conf + diff --git a/forecast.py b/forecast.py new file mode 100644 index 0000000..52bbf09 --- /dev/null +++ b/forecast.py @@ -0,0 +1,1566 @@ +import json + +# Exemple de JSON +json_str = ''' +{ + "cod": "200", + "message": 0, + "cnt": 40, + "list": [ + { + "dt": 1718312400, + "main": { + "temp": 12.84, + "feels_like": 12.61, + "temp_min": 12.84, + "temp_max": 13.87, + "pressure": 1010, + "sea_level": 1010, + "grnd_level": 1004, + "humidity": 93, + "temp_kf": -1.03 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10n" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 6.07, + "deg": 200, + "gust": 11.82 + }, + "visibility": 10000, + "pop": 1, + "rain": { + "3h": 1.17 + }, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-06-13 21:00:00" + }, + { + "dt": 1718323200, + "main": { + "temp": 14.27, + "feels_like": 14.21, + "temp_min": 14.27, + "temp_max": 15.25, + "pressure": 1009, + "sea_level": 1009, + "grnd_level": 1002, + "humidity": 94, + "temp_kf": -0.98 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10n" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 5.33, + "deg": 255, + "gust": 9.41 + }, + "visibility": 10000, + "pop": 1, + "rain": { + "3h": 0.18 + }, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-06-14 00:00:00" + }, + { + "dt": 1718334000, + "main": { + "temp": 13.46, + "feels_like": 13.37, + "temp_min": 13.46, + "temp_max": 13.46, + "pressure": 1008, + "sea_level": 1008, + "grnd_level": 1002, + "humidity": 96, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10n" + } + ], + "clouds": { + "all": 77 + }, + "wind": { + "speed": 3.98, + "deg": 240, + "gust": 10.97 + }, + "visibility": 10000, + "pop": 0.2, + "rain": { + "3h": 0.1 + }, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-06-14 03:00:00" + }, + { + "dt": 1718344800, + "main": { + "temp": 13.73, + "feels_like": 13.59, + "temp_min": 13.73, + "temp_max": 13.73, + "pressure": 1008, + "sea_level": 1008, + "grnd_level": 1002, + "humidity": 93, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10d" + } + ], + "clouds": { + "all": 89 + }, + "wind": { + "speed": 4.01, + "deg": 235, + "gust": 9.83 + }, + "visibility": 10000, + "pop": 0.2, + "rain": { + "3h": 0.2 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-14 06:00:00" + }, + { + "dt": 1718355600, + "main": { + "temp": 16.37, + "feels_like": 16.1, + "temp_min": 16.37, + "temp_max": 16.37, + "pressure": 1008, + "sea_level": 1008, + "grnd_level": 1002, + "humidity": 78, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10d" + } + ], + "clouds": { + "all": 95 + }, + "wind": { + "speed": 6.09, + "deg": 234, + "gust": 10.15 + }, + "visibility": 10000, + "pop": 0.3, + "rain": { + "3h": 0.19 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-14 09:00:00" + }, + { + "dt": 1718366400, + "main": { + "temp": 17.7, + "feels_like": 17.46, + "temp_min": 17.7, + "temp_max": 17.7, + "pressure": 1007, + "sea_level": 1007, + "grnd_level": 1001, + "humidity": 74, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10d" + } + ], + "clouds": { + "all": 71 + }, + "wind": { + "speed": 9.72, + "deg": 237, + "gust": 12.77 + }, + "visibility": 10000, + "pop": 1, + "rain": { + "3h": 1.55 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-14 12:00:00" + }, + { + "dt": 1718377200, + "main": { + "temp": 17.32, + "feels_like": 16.8, + "temp_min": 17.32, + "temp_max": 17.32, + "pressure": 1006, + "sea_level": 1006, + "grnd_level": 1001, + "humidity": 65, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10d" + } + ], + "clouds": { + "all": 99 + }, + "wind": { + "speed": 9.77, + "deg": 238, + "gust": 13.2 + }, + "visibility": 10000, + "pop": 0.89, + "rain": { + "3h": 0.45 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-14 15:00:00" + }, + { + "dt": 1718388000, + "main": { + "temp": 14.4, + "feels_like": 14.04, + "temp_min": 14.4, + "temp_max": 14.4, + "pressure": 1006, + "sea_level": 1006, + "grnd_level": 1000, + "humidity": 82, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10d" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 7.62, + "deg": 244, + "gust": 11.87 + }, + "visibility": 10000, + "pop": 1, + "rain": { + "3h": 0.57 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-14 18:00:00" + }, + { + "dt": 1718398800, + "main": { + "temp": 11.37, + "feels_like": 10.89, + "temp_min": 11.37, + "temp_max": 11.37, + "pressure": 1007, + "sea_level": 1007, + "grnd_level": 1001, + "humidity": 89, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10n" + } + ], + "clouds": { + "all": 28 + }, + "wind": { + "speed": 7.04, + "deg": 245, + "gust": 13.94 + }, + "visibility": 10000, + "pop": 1, + "rain": { + "3h": 0.83 + }, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-06-14 21:00:00" + }, + { + "dt": 1718409600, + "main": { + "temp": 9.59, + "feels_like": 6.98, + "temp_min": 9.59, + "temp_max": 9.59, + "pressure": 1008, + "sea_level": 1008, + "grnd_level": 1002, + "humidity": 91, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10n" + } + ], + "clouds": { + "all": 34 + }, + "wind": { + "speed": 5.26, + "deg": 254, + "gust": 13.98 + }, + "visibility": 10000, + "pop": 1, + "rain": { + "3h": 0.3 + }, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-06-15 00:00:00" + }, + { + "dt": 1718420400, + "main": { + "temp": 9.15, + "feels_like": 6.91, + "temp_min": 9.15, + "temp_max": 9.15, + "pressure": 1008, + "sea_level": 1008, + "grnd_level": 1003, + "humidity": 92, + "temp_kf": 0 + }, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "ciel dégagé", + "icon": "01n" + } + ], + "clouds": { + "all": 3 + }, + "wind": { + "speed": 4.1, + "deg": 245, + "gust": 11.89 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-06-15 03:00:00" + }, + { + "dt": 1718431200, + "main": { + "temp": 12.35, + "feels_like": 11.83, + "temp_min": 12.35, + "temp_max": 12.35, + "pressure": 1009, + "sea_level": 1009, + "grnd_level": 1003, + "humidity": 84, + "temp_kf": 0 + }, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "ciel dégagé", + "icon": "01d" + } + ], + "clouds": { + "all": 3 + }, + "wind": { + "speed": 6.05, + "deg": 243, + "gust": 12.04 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-15 06:00:00" + }, + { + "dt": 1718442000, + "main": { + "temp": 14.24, + "feels_like": 13.78, + "temp_min": 14.24, + "temp_max": 14.24, + "pressure": 1009, + "sea_level": 1009, + "grnd_level": 1003, + "humidity": 79, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10d" + } + ], + "clouds": { + "all": 70 + }, + "wind": { + "speed": 7.86, + "deg": 243, + "gust": 12.51 + }, + "visibility": 10000, + "pop": 0.68, + "rain": { + "3h": 0.37 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-15 09:00:00" + }, + { + "dt": 1718452800, + "main": { + "temp": 16.61, + "feels_like": 16.05, + "temp_min": 16.61, + "temp_max": 16.61, + "pressure": 1008, + "sea_level": 1008, + "grnd_level": 1003, + "humidity": 66, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10d" + } + ], + "clouds": { + "all": 85 + }, + "wind": { + "speed": 10, + "deg": 247, + "gust": 13.31 + }, + "visibility": 10000, + "pop": 0.72, + "rain": { + "3h": 0.37 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-15 12:00:00" + }, + { + "dt": 1718463600, + "main": { + "temp": 16.72, + "feels_like": 16.38, + "temp_min": 16.72, + "temp_max": 16.72, + "pressure": 1009, + "sea_level": 1009, + "grnd_level": 1003, + "humidity": 74, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10d" + } + ], + "clouds": { + "all": 93 + }, + "wind": { + "speed": 10.53, + "deg": 251, + "gust": 14.02 + }, + "visibility": 10000, + "pop": 1, + "rain": { + "3h": 0.49 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-15 15:00:00" + }, + { + "dt": 1718474400, + "main": { + "temp": 15.92, + "feels_like": 15.5, + "temp_min": 15.92, + "temp_max": 15.92, + "pressure": 1009, + "sea_level": 1009, + "grnd_level": 1004, + "humidity": 74, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10d" + } + ], + "clouds": { + "all": 66 + }, + "wind": { + "speed": 7.08, + "deg": 254, + "gust": 10.51 + }, + "visibility": 10000, + "pop": 1, + "rain": { + "3h": 0.59 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-15 18:00:00" + }, + { + "dt": 1718485200, + "main": { + "temp": 13.32, + "feels_like": 12.9, + "temp_min": 13.32, + "temp_max": 13.32, + "pressure": 1011, + "sea_level": 1011, + "grnd_level": 1005, + "humidity": 84, + "temp_kf": 0 + }, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "nuageux", + "icon": "04n" + } + ], + "clouds": { + "all": 55 + }, + "wind": { + "speed": 4.24, + "deg": 235, + "gust": 9.64 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-06-15 21:00:00" + }, + { + "dt": 1718496000, + "main": { + "temp": 11, + "feels_like": 10.64, + "temp_min": 11, + "temp_max": 11, + "pressure": 1010, + "sea_level": 1010, + "grnd_level": 1005, + "humidity": 95, + "temp_kf": 0 + }, + "weather": [ + { + "id": 802, + "main": "Clouds", + "description": "partiellement nuageux", + "icon": "03n" + } + ], + "clouds": { + "all": 45 + }, + "wind": { + "speed": 3.45, + "deg": 236, + "gust": 10.02 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-06-16 00:00:00" + }, + { + "dt": 1718506800, + "main": { + "temp": 10.9, + "feels_like": 10.53, + "temp_min": 10.9, + "temp_max": 10.9, + "pressure": 1009, + "sea_level": 1009, + "grnd_level": 1004, + "humidity": 95, + "temp_kf": 0 + }, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "couvert", + "icon": "04n" + } + ], + "clouds": { + "all": 95 + }, + "wind": { + "speed": 2.98, + "deg": 209, + "gust": 5.32 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-06-16 03:00:00" + }, + { + "dt": 1718517600, + "main": { + "temp": 13.64, + "feels_like": 13.44, + "temp_min": 13.64, + "temp_max": 13.64, + "pressure": 1009, + "sea_level": 1009, + "grnd_level": 1003, + "humidity": 91, + "temp_kf": 0 + }, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "nuageux", + "icon": "04d" + } + ], + "clouds": { + "all": 83 + }, + "wind": { + "speed": 3.29, + "deg": 198, + "gust": 8.26 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-16 06:00:00" + }, + { + "dt": 1718528400, + "main": { + "temp": 13.48, + "feels_like": 13.42, + "temp_min": 13.48, + "temp_max": 13.48, + "pressure": 1008, + "sea_level": 1008, + "grnd_level": 1003, + "humidity": 97, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10d" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 3.99, + "deg": 159, + "gust": 8.22 + }, + "visibility": 5488, + "pop": 1, + "rain": { + "3h": 1.39 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-16 09:00:00" + }, + { + "dt": 1718539200, + "main": { + "temp": 16.53, + "feels_like": 16.64, + "temp_min": 16.53, + "temp_max": 16.53, + "pressure": 1007, + "sea_level": 1007, + "grnd_level": 1001, + "humidity": 92, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10d" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 2.71, + "deg": 215, + "gust": 6.78 + }, + "visibility": 10000, + "pop": 1, + "rain": { + "3h": 2.85 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-16 12:00:00" + }, + { + "dt": 1718550000, + "main": { + "temp": 18.94, + "feels_like": 18.82, + "temp_min": 18.94, + "temp_max": 18.94, + "pressure": 1007, + "sea_level": 1007, + "grnd_level": 1002, + "humidity": 74, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10d" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 4.25, + "deg": 265, + "gust": 6.19 + }, + "visibility": 10000, + "pop": 0.98, + "rain": { + "3h": 0.43 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-16 15:00:00" + }, + { + "dt": 1718560800, + "main": { + "temp": 17.03, + "feels_like": 16.9, + "temp_min": 17.03, + "temp_max": 17.03, + "pressure": 1008, + "sea_level": 1008, + "grnd_level": 1003, + "humidity": 81, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10d" + } + ], + "clouds": { + "all": 97 + }, + "wind": { + "speed": 4.97, + "deg": 228, + "gust": 7.51 + }, + "visibility": 10000, + "pop": 0.96, + "rain": { + "3h": 0.51 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-16 18:00:00" + }, + { + "dt": 1718571600, + "main": { + "temp": 13.61, + "feels_like": 13.56, + "temp_min": 13.61, + "temp_max": 13.61, + "pressure": 1009, + "sea_level": 1009, + "grnd_level": 1004, + "humidity": 97, + "temp_kf": 0 + }, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "couvert", + "icon": "04n" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 2.57, + "deg": 197, + "gust": 3.7 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-06-16 21:00:00" + }, + { + "dt": 1718582400, + "main": { + "temp": 13.14, + "feels_like": 13.09, + "temp_min": 13.14, + "temp_max": 13.14, + "pressure": 1009, + "sea_level": 1009, + "grnd_level": 1004, + "humidity": 99, + "temp_kf": 0 + }, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "couvert", + "icon": "04n" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 2.82, + "deg": 193, + "gust": 6.37 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-06-17 00:00:00" + }, + { + "dt": 1718593200, + "main": { + "temp": 13.45, + "feels_like": 13.41, + "temp_min": 13.45, + "temp_max": 13.45, + "pressure": 1009, + "sea_level": 1009, + "grnd_level": 1004, + "humidity": 98, + "temp_kf": 0 + }, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "nuageux", + "icon": "04n" + } + ], + "clouds": { + "all": 54 + }, + "wind": { + "speed": 3.36, + "deg": 207, + "gust": 9.2 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-06-17 03:00:00" + }, + { + "dt": 1718604000, + "main": { + "temp": 15.25, + "feels_like": 15.34, + "temp_min": 15.25, + "temp_max": 15.25, + "pressure": 1010, + "sea_level": 1010, + "grnd_level": 1004, + "humidity": 96, + "temp_kf": 0 + }, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "nuageux", + "icon": "04d" + } + ], + "clouds": { + "all": 77 + }, + "wind": { + "speed": 3.52, + "deg": 202, + "gust": 7.94 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-17 06:00:00" + }, + { + "dt": 1718614800, + "main": { + "temp": 19.13, + "feels_like": 19.08, + "temp_min": 19.13, + "temp_max": 19.13, + "pressure": 1010, + "sea_level": 1010, + "grnd_level": 1005, + "humidity": 76, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10d" + } + ], + "clouds": { + "all": 81 + }, + "wind": { + "speed": 4.73, + "deg": 209, + "gust": 6.02 + }, + "visibility": 8886, + "pop": 0.59, + "rain": { + "3h": 0.37 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-17 09:00:00" + }, + { + "dt": 1718625600, + "main": { + "temp": 19.29, + "feels_like": 19.36, + "temp_min": 19.29, + "temp_max": 19.29, + "pressure": 1011, + "sea_level": 1011, + "grnd_level": 1005, + "humidity": 80, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10d" + } + ], + "clouds": { + "all": 90 + }, + "wind": { + "speed": 6.87, + "deg": 217, + "gust": 8.9 + }, + "visibility": 10000, + "pop": 1, + "rain": { + "3h": 2.54 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-17 12:00:00" + }, + { + "dt": 1718636400, + "main": { + "temp": 20.2, + "feels_like": 20.16, + "temp_min": 20.2, + "temp_max": 20.2, + "pressure": 1011, + "sea_level": 1011, + "grnd_level": 1005, + "humidity": 72, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10d" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 7.59, + "deg": 228, + "gust": 9.18 + }, + "visibility": 10000, + "pop": 1, + "rain": { + "3h": 0.43 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-17 15:00:00" + }, + { + "dt": 1718647200, + "main": { + "temp": 17.98, + "feels_like": 18.03, + "temp_min": 17.98, + "temp_max": 17.98, + "pressure": 1012, + "sea_level": 1012, + "grnd_level": 1006, + "humidity": 84, + "temp_kf": 0 + }, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "couvert", + "icon": "04d" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 4.84, + "deg": 228, + "gust": 8 + }, + "visibility": 10000, + "pop": 0.54, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-17 18:00:00" + }, + { + "dt": 1718658000, + "main": { + "temp": 14.92, + "feels_like": 14.97, + "temp_min": 14.92, + "temp_max": 14.92, + "pressure": 1012, + "sea_level": 1012, + "grnd_level": 1007, + "humidity": 96, + "temp_kf": 0 + }, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "couvert", + "icon": "04n" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 1.94, + "deg": 218, + "gust": 2.03 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-06-17 21:00:00" + }, + { + "dt": 1718668800, + "main": { + "temp": 14.75, + "feels_like": 14.81, + "temp_min": 14.75, + "temp_max": 14.75, + "pressure": 1012, + "sea_level": 1012, + "grnd_level": 1007, + "humidity": 97, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10n" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 2.31, + "deg": 206, + "gust": 3.75 + }, + "visibility": 10000, + "pop": 0.2, + "rain": { + "3h": 0.14 + }, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-06-18 00:00:00" + }, + { + "dt": 1718679600, + "main": { + "temp": 14.68, + "feels_like": 14.79, + "temp_min": 14.68, + "temp_max": 14.68, + "pressure": 1011, + "sea_level": 1011, + "grnd_level": 1005, + "humidity": 99, + "temp_kf": 0 + }, + "weather": [ + { + "id": 501, + "main": "Rain", + "description": "pluie modérée", + "icon": "10n" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 2.01, + "deg": 4, + "gust": 2.23 + }, + "visibility": 10000, + "pop": 1, + "rain": { + "3h": 3.44 + }, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-06-18 03:00:00" + }, + { + "dt": 1718690400, + "main": { + "temp": 14.81, + "feels_like": 14.91, + "temp_min": 14.81, + "temp_max": 14.81, + "pressure": 1011, + "sea_level": 1011, + "grnd_level": 1005, + "humidity": 98, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10d" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 2.59, + "deg": 79, + "gust": 3.89 + }, + "visibility": 10000, + "pop": 1, + "rain": { + "3h": 1.62 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-18 06:00:00" + }, + { + "dt": 1718701200, + "main": { + "temp": 16.56, + "feels_like": 16.52, + "temp_min": 16.56, + "temp_max": 16.56, + "pressure": 1011, + "sea_level": 1011, + "grnd_level": 1006, + "humidity": 86, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10d" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 3.67, + "deg": 64, + "gust": 5.47 + }, + "visibility": 10000, + "pop": 0.61, + "rain": { + "3h": 0.59 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-18 09:00:00" + }, + { + "dt": 1718712000, + "main": { + "temp": 18.36, + "feels_like": 18.31, + "temp_min": 18.36, + "temp_max": 18.36, + "pressure": 1011, + "sea_level": 1011, + "grnd_level": 1006, + "humidity": 79, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10d" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 4.29, + "deg": 63, + "gust": 4.83 + }, + "visibility": 10000, + "pop": 0.47, + "rain": { + "3h": 0.13 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-18 12:00:00" + }, + { + "dt": 1718722800, + "main": { + "temp": 19.51, + "feels_like": 19.5, + "temp_min": 19.51, + "temp_max": 19.51, + "pressure": 1011, + "sea_level": 1011, + "grnd_level": 1005, + "humidity": 76, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10d" + } + ], + "clouds": { + "all": 99 + }, + "wind": { + "speed": 3.58, + "deg": 48, + "gust": 4.01 + }, + "visibility": 10000, + "pop": 0.2, + "rain": { + "3h": 0.15 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-18 15:00:00" + }, + { + "dt": 1718733600, + "main": { + "temp": 17.82, + "feels_like": 17.93, + "temp_min": 17.82, + "temp_max": 17.82, + "pressure": 1010, + "sea_level": 1010, + "grnd_level": 1005, + "humidity": 87, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10d" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 4.41, + "deg": 31, + "gust": 6.95 + }, + "visibility": 10000, + "pop": 0.25, + "rain": { + "3h": 0.36 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-06-18 18:00:00" + } + ], + "city": { + "id": 3009239, + "name": "La Gacilly", + "coord": { + "lat": 47.7656, + "lon": -2.1322 + }, + "country": "FR", + "population": 2453, + "timezone": 7200, + "sunrise": 1718251782, + "sunset": 1718309266 + } +} +''' + +# Décoder le JSON +data = json.loads(json_str) + +# Extraire les 6 premières valeurs du champ "all" +cloud_values = [item['clouds']['all'] for item in data['list'][:6]] + +# Afficher les valeurs extraites +for i, value in enumerate(cloud_values, start=1): + print(f"Cloud coverage for point {i}: {value}") + +# Calculer la moyenne +average_cloud_coverage = sum(cloud_values) / len(cloud_values) + +# Afficher les valeurs extraites et la moyenne +print("Cloud coverage values:", cloud_values) +print("Average cloud coverage:", average_cloud_coverage) diff --git a/fumeeOff.sh b/fumeeOff.sh new file mode 100755 index 0000000..b2b349f --- /dev/null +++ b/fumeeOff.sh @@ -0,0 +1,4 @@ +#!/bin/sh + + + diff --git a/fumeeOn.sh b/fumeeOn.sh new file mode 100755 index 0000000..b2b349f --- /dev/null +++ b/fumeeOn.sh @@ -0,0 +1,4 @@ +#!/bin/sh + + + diff --git a/getgooglecal.py b/getgooglecal.py new file mode 100644 index 0000000..f5c4ed2 --- /dev/null +++ b/getgooglecal.py @@ -0,0 +1,56 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# ce programme interroge l agenda google et renvoie les taches du jour +# dans un fichier texte + + +import time +import os + + +############# Parametres ################################# +# on utilise gcalcli qui doit etre installe + + +# Nom du calendrier google qui contient les actions Domoticz +domoticz_cal="Domoticz" + +#options de la ligne de commande cf doc google +options="--tsv --military" +agenda_start="00:00" +agenda_end="23:59" + +# fichier et chemin pour agenda +rep="/var/tmp/" +file="googlecal.txt" + + +#debug = 1 on affiche les chaines de caracteres recues +debug=1 + + + +# fin du parametrage # + + +############### fin des parametres ############################# + + +datej=time.strftime('%Y%m%d',time.localtime()) +#gcalcli --cal=Domoticz agenda '20141230T00:00' '20141230T23:59" --tsv --military +lignecde="gcalcli --cal="+domoticz_cal+" agenda "+"'"+datej+"T"+agenda_start+"' '"+datej+"T"+agenda_end+"' "+options +lignecde=lignecde+" > "+rep+file + +if debug!=0: + print datej + print lignecde + +os.system(lignecde) + + +if debug!=0: + print datej + print lignecde + os.system ('cat /var/tmp/googlecal.txt') + diff --git a/grafana.sh b/grafana.sh new file mode 100644 index 0000000..5eec59f --- /dev/null +++ b/grafana.sh @@ -0,0 +1,5 @@ +apt-get install -y adduser libfontconfig1 musl +wget https://dl.grafana.com/enterprise/release/grafana-enterprise_10.2.3_amd64.deb +dpkg -i grafana-enterprise_10.2.3_amd64.deb +grafana-cli plugins install frser-sqlite-datasource + diff --git a/hum.sh b/hum.sh new file mode 100755 index 0000000..477edbc --- /dev/null +++ b/hum.sh @@ -0,0 +1,34 @@ +#!/bin/bash +i=0 + +cd /opt/domoticz/scripts/ +export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games:/usr/local/lib/ +while ["$temp" -eq ""] +do + rm /tmp/digiterm.tmp + /opt/domoticz/scripts/digiterm --raw --no-info >/tmp/digiterm.tmp 2>>/var/log/syslog + + temp=`cat /tmp/digiterm.tmp |awk -F "," '{ print $2 }'|awk -F "@" '{print $1}'` + hum=`cat /tmp/digiterm.tmp |awk -F "," '{ print $1 }'|awk -F "#" '{print $2}'` + + echo "HUM " $temp "--" $hum >>/var/log/syslog + + if [ -z "$temp" -a -z "$hum" ]; + then + echo "Error: Value variable empty" + else + echo "HUM " $temp "--" $hum + json="http://localhost:81/json.htm?type=command¶m=udevice&idx=68&svalue=$temp;$hum;0" + echo "HUM " $json >>/var/log/syslog + curl -s -i -H "Accept: application/json" $json >/dev/null 2>>/var/log/syslog + exit 0 + fi + sleep 1 + i+=1 + if [[ "$i" -ge 3 ]]; + then + exit 0 + fi +done + +exit 0 diff --git a/hum2.sh b/hum2.sh new file mode 100755 index 0000000..5421bb2 --- /dev/null +++ b/hum2.sh @@ -0,0 +1,11 @@ +#!/bin/bash +i=0 + +while [ 1 ] +do + /opt/domoticz/scripts/hum.sh + sleep 60 + +done + +exit 0 diff --git a/i2c.py b/i2c.py new file mode 100755 index 0000000..5750425 --- /dev/null +++ b/i2c.py @@ -0,0 +1,13 @@ +import smbus +import time + +# Remplacer 0 par 1 si nouveau Raspberry +bus = smbus.SMBus(1) +address = 0x12 + +print "Envoi de la valeur 3" +bus.write_byte(address, 3) +# Pause de 1 seconde pour laisser le temps au traitement de se faire +time.sleep(1) +reponse = bus.read_byte(address) +print "La reponse de l'arduino : ", reponse diff --git a/i2cs.py b/i2cs.py new file mode 100755 index 0000000..34283be --- /dev/null +++ b/i2cs.py @@ -0,0 +1,21 @@ +#!/usr/bin/python + +from smbus import SMBus +import time +bus = SMBus(1) +slaveAddress = 0x12 +data_received_from_Arduino = "" +data_to_send_to_Arduino = "Hello Uno" + + +def StringToBytes(val): + retVal = [] + for c in val: + retVal.append(c) + return retVal + +bus.write_byte(slaveAddress,1) +time.sleep(0.2) +data_received_from_Arduino = bus.read_i2c_block_data(slaveAddress, 0, 12) +print(data_received_from_Arduino) + diff --git a/i2cs2.py b/i2cs2.py new file mode 100755 index 0000000..ef067ff --- /dev/null +++ b/i2cs2.py @@ -0,0 +1,33 @@ +#!/usr/bin/python + +import smbus +import time +import os +import subprocess + +bus = smbus.SMBus(1) +address = 0x12 + +print "Envoi de la valeur 3 indiquant le debut de la demande" +bus.write_byte(address, 3) +# Pause de 1 seconde pour laisser le temps au traitement de se faire +time.sleep(1) + +data = "" +for i in range(0, 200): + data += chr(bus.read_byte(address)); +print data + +datas = data.split("|") +i = 0 +for d in datas: + i = i + 1 + if i <= 7 : + print d + print "Send subprocess : curl http://localhost:81/json.htm?type=command¶m=udevice&" + d + try: + subprocess.Popen(["/usr/bin/curl", "http://localhost:81/json.htm?type=command¶m=udevice&" + d ]) + time.sleep(0.5) + except: + print "Error occured " + d +print "Finish" diff --git a/index.html b/index.html new file mode 100644 index 0000000..c875c40 --- /dev/null +++ b/index.html @@ -0,0 +1,1611 @@ + + + + 2015-08-29 + 76351 + HAVRE + 4 + 4 + 2 + 3 + 3 + + http://www.lcsqa.org/aasqa/code/05 + + + 2015-08-29 + 76540 + ROUEN + 4 + 4 + 2 + 3 + 1 + + http://www.lcsqa.org/aasqa/code/25 + + + 2015-08-29 + 27229 + EVREUX + 4 + 4 + 1 + 3 + + + http://www.lcsqa.org/aasqa/code/25 + + + 2015-08-29 + 13001 + AIX-EN-PROVENCE + 6 + 6 + 2 + 3 + + + http://www.lcsqa.org/aasqa/code/03 + + + 2015-08-29 + 13005 + AUBAGNE + 6 + 6 + 2 + 3 + + + http://www.lcsqa.org/aasqa/code/03 + + + 2015-08-29 + 84007 + AVIGNON + 6 + 6 + 2 + 3 + + + http://www.lcsqa.org/aasqa/code/03 + + + 2015-08-29 + 83023 + BRIGNOLES + 6 + 6 + + 3 + + + http://www.lcsqa.org/aasqa/code/03 + + + 2015-08-29 + 83069 + HYERES + 6 + 6 + + 2 + + + http://www.lcsqa.org/aasqa/code/03 + + + 2015-08-29 + 13055 + MARSEILLE + 6 + 6 + 3 + 3 + 1 + + http://www.lcsqa.org/aasqa/code/03 + + + 2015-08-29 + 83137 + TOULON + 5 + 5 + 3 + 3 + + + http://www.lcsqa.org/aasqa/code/03 + + + 2015-08-29 + 53130 + LAVAL + 5 + + + + + + http://www.lcsqa.org/aasqa/code/23 + + + 2015-08-29 + 44109 + NANTES + 6 + + + + + + http://www.lcsqa.org/aasqa/code/23 + + + 2015-08-29 + 49099 + CHOLET + 6 + + + + + + http://www.lcsqa.org/aasqa/code/23 + + + 2015-08-29 + 85191 + ROCHE-SUR-YON + 6 + + + + + + http://www.lcsqa.org/aasqa/code/23 + + + 2015-08-29 + 44184 + SAINT-NAZAIRE + 5 + + + + + + http://www.lcsqa.org/aasqa/code/23 + + + 2015-08-29 + 72181 + MANS + 5 + + + + + + http://www.lcsqa.org/aasqa/code/23 + + + 2015-08-29 + 49007 + ANGERS + 5 + + + + + + http://www.lcsqa.org/aasqa/code/23 + + + 2015-08-29 + 06029 + CANNES + 6 + 6 + 3 + 3 + + + http://www.lcsqa.org/aasqa/code/24 + + + 2015-08-29 + 05061 + GAP + 5 + 5 + 1 + 4 + + + http://www.lcsqa.org/aasqa/code/24 + + + 2015-08-29 + 06088 + NICE + 6 + 6 + 3 + 3 + + + http://www.lcsqa.org/aasqa/code/24 + + + 2015-08-29 + 75056 + PARIS + 4 + 4 + 3 + 3 + + + http://www.lcsqa.org/aasqa/code/04 + + + 2015-08-29 + 97209 + FORT-DE-FRANCE + 5 + 1 + 1 + 4 + 1 + + http://www.lcsqa.org/aasqa/code/39 + + + 2015-08-29 + 61001 + ALENCON + 3 + 2 + 1 + 3 + + + http://www.lcsqa.org/aasqa/code/21 + + + 2015-08-29 + 14118 + CAEN + 3 + 2 + 1 + 3 + + + http://www.lcsqa.org/aasqa/code/21 + + + 2015-08-29 + 50129 + CHERBOURG-OCTEVILLE + 3 + 2 + 2 + 3 + 1 + + http://www.lcsqa.org/aasqa/code/21 + + + 2015-08-29 + 14366 + LISIEUX + 3 + 2 + 1 + 3 + + + http://www.lcsqa.org/aasqa/code/21 + + + 2015-08-29 + 50502 + SAINT-LO + 3 + 2 + 1 + 3 + + + http://www.lcsqa.org/aasqa/code/21 + + + 2015-08-29 + 81004 + ALBI + 5 + + + + + + http://www.lcsqa.org/aasqa/code/12 + + + 2015-08-29 + 81065 + CASTRES + 5 + + + + + + http://www.lcsqa.org/aasqa/code/12 + + + 2015-08-29 + 65286 + LOURDES + 5 + + + + + + http://www.lcsqa.org/aasqa/code/12 + + + 2015-08-29 + 65440 + TARBES + 5 + + + + + + http://www.lcsqa.org/aasqa/code/12 + + + 2015-08-29 + 31555 + TOULOUSE + 5 + + + + + + http://www.lcsqa.org/aasqa/code/12 + + + 2015-08-29 + 79005 + AIRVAULT + 4 + 4 + 1 + 2 + 1 + + http://www.lcsqa.org/aasqa/code/09 + + + 2015-08-29 + 16015 + ANGOULEME + 4 + 4 + 1 + 3 + + + http://www.lcsqa.org/aasqa/code/09 + + + 2015-08-29 + 16102 + COGNAC + 4 + 4 + 1 + 2 + 1 + + http://www.lcsqa.org/aasqa/code/09 + + + 2015-08-29 + 17300 + ROCHELLE + 4 + 4 + 1 + 2 + + + http://www.lcsqa.org/aasqa/code/09 + + + 2015-08-29 + 79191 + NIORT + 4 + 4 + 1 + 2 + + + http://www.lcsqa.org/aasqa/code/09 + + + 2015-08-29 + 86194 + POITIERS + 4 + 4 + 1 + 2 + + + http://www.lcsqa.org/aasqa/code/09 + + + 2015-08-29 + 29019 + BREST + 4 + + + + + + http://www.lcsqa.org/aasqa/code/19 + + + 2015-08-29 + 35115 + FOUGERES + 4 + + + + + + http://www.lcsqa.org/aasqa/code/19 + + + 2015-08-29 + 56121 + LORIENT + 4 + + + + + + http://www.lcsqa.org/aasqa/code/19 + + + 2015-08-29 + 22278 + SAINT-BRIEUC + 4 + + + + + + http://www.lcsqa.org/aasqa/code/19 + + + 2015-08-29 + 35288 + SAINT-MALO + 4 + + + + + + http://www.lcsqa.org/aasqa/code/19 + + + 2015-08-29 + 56260 + VANNES + 4 + + + + + + http://www.lcsqa.org/aasqa/code/19 + + + 2015-08-29 + 25388 + MONTBELIARD + 5 + 5 + 1 + 2 + + + http://www.lcsqa.org/aasqa/code/82 + + + 2015-08-29 + 70550 + VESOUL + 5 + 5 + 1 + 2 + + + http://www.lcsqa.org/aasqa/code/82 + + + 2015-08-29 + 90010 + BELFORT + 5 + 5 + 1 + 2 + + + http://www.lcsqa.org/aasqa/code/82 + + + 2015-08-29 + 39300 + LONS-LE-SAUNIER + 7 + 7 + 1 + 4 + + + http://www.lcsqa.org/aasqa/code/82 + + + 2015-08-29 + 25056 + BESANCON + 6 + 6 + 2 + 3 + + + http://www.lcsqa.org/aasqa/code/82 + + + 2015-08-29 + 39198 + DOLE + 6 + 6 + 1 + 2 + 1 + + http://www.lcsqa.org/aasqa/code/82 + + + 2015-08-29 + 68066 + COLMAR + 6 + 6 + 2 + 2 + 1 + 6(O3) / 6(O3) + http://www.lcsqa.org/aasqa/code/16 + + + 2015-08-29 + 68349 + VILLAGE-NEUF + 6 + 6 + 1 + 3 + + + http://www.lcsqa.org/aasqa/code/16 + + + 2015-08-29 + 68224 + MULHOUSE + 6 + 6 + 1 + 2 + + 5(O3) / 6(O3) + http://www.lcsqa.org/aasqa/code/16 + + + 2015-08-29 + 67308 + MUNCHHAUSEN + 5 + 5 + 2 + 4 + 1 + + http://www.lcsqa.org/aasqa/code/16 + + + 2015-08-29 + 67482 + STRASBOURG + 5 + 5 + 2 + 3 + 1 + 5(O3) / 5(O3) + http://www.lcsqa.org/aasqa/code/16 + + + 2015-08-29 + 67165 + GRANDFONTAINE + 4 + 4 + + + + + http://www.lcsqa.org/aasqa/code/16 + + + 2015-08-29 + 67371 + PETITE-PIERRE + 5 + 5 + 1 + + + + http://www.lcsqa.org/aasqa/code/16 + + + 2015-08-29 + 19031 + BRIVE-LA-GAILLARDE + 5 + + + + + + http://www.lcsqa.org/aasqa/code/35 + + + 2015-08-29 + 23096 + GUERET + 5 + + + + + + http://www.lcsqa.org/aasqa/code/35 + + + 2015-08-29 + 87154 + SAINT-JUNIEN + 5 + + + + + + http://www.lcsqa.org/aasqa/code/35 + + + 2015-08-29 + 87085 + LIMOGES + 5 + + + + + + http://www.lcsqa.org/aasqa/code/35 + + + 2015-08-29 + 19272 + TULLE + 4 + + + + + + http://www.lcsqa.org/aasqa/code/35 + + + 2015-08-29 + 89024 + AUXERRE + 5 + + + + + + http://www.lcsqa.org/aasqa/code/26 + + + 2015-08-29 + 21231 + DIJON + 5 + + + + + La qualité de l'air reste stable + http://www.lcsqa.org/aasqa/code/26 + + + 2015-08-29 + 58194 + NEVERS + 5 + + + + + + http://www.lcsqa.org/aasqa/code/26 + + + 2015-08-29 + 89387 + SENS + 5 + + + + + + http://www.lcsqa.org/aasqa/code/26 + + + 2015-08-29 + 71076 + CHALON-SUR-SAONE + 5 + + + + + + http://www.lcsqa.org/aasqa/code/32 + + + 2015-08-29 + 71306 + MONTCEAU-LES-MINES + 5 + + + + + + http://www.lcsqa.org/aasqa/code/32 + + + 2015-08-29 + 71270 + MACON + 5 + + + + + + http://www.lcsqa.org/aasqa/code/32 + + + 2015-08-29 + 45234 + ORLEANS + 4 + 4 + 1 + 1 + + + http://www.lcsqa.org/aasqa/code/34 + + + 2015-08-29 + 18033 + BOURGES + 4 + 4 + 1 + 2 + + + http://www.lcsqa.org/aasqa/code/34 + + + 2015-08-29 + 37261 + TOURS + 4 + 4 + 1 + 3 + + + http://www.lcsqa.org/aasqa/code/34 + + + 2015-08-29 + 28085 + CHARTRES + 4 + 4 + 1 + 2 + + + http://www.lcsqa.org/aasqa/code/34 + + + 2015-08-29 + 36044 + CHATEAUROUX + 4 + 4 + 1 + 2 + + + http://www.lcsqa.org/aasqa/code/34 + + + 2015-08-29 + 41018 + BLOIS + 4 + 4 + 1 + 2 + + + http://www.lcsqa.org/aasqa/code/34 + + + 2015-08-29 + 28134 + DREUX + 4 + 4 + 1 + 2 + + + http://www.lcsqa.org/aasqa/code/34 + + + 2015-08-29 + 45208 + MONTARGIS + 4 + 4 + 1 + 2 + + + http://www.lcsqa.org/aasqa/code/34 + + + 2015-08-29 + 18279 + VIERZON + 4 + 4 + 1 + 2 + + + http://www.lcsqa.org/aasqa/code/34 + + + 2015-08-29 + 38185 + GRENOBLE + 6 + 6 + 1 + 4 + 1 + Samedi 29 août : la qualité de l'air sera médiocre. Les indices prévus sont majoritairement égaux à 6. Le polluant déterminant cet indice est l'ozone. Les prévisions de trafic routier important et la situation météorologique favoriseront le transport et la production d'ozone dans toute la vallée du Rhône ainsi que sur les vallées alpines. + http://www.lcsqa.org/aasqa/code/15 + + + 2015-08-29 + 42218 + SAINT-ETIENNE + 5 + 5 + 2 + 3 + 1 + Samedi 29 août : la qualité de l'air sera médiocre. Les indices prévus sont majoritairement égaux à 6. Le polluant déterminant cet indice est l'ozone. Les prévisions de trafic routier important et la situation météorologique favoriseront le transport et la production d'ozone dans toute la vallée du Rhône ainsi que sur les vallées alpines. + http://www.lcsqa.org/aasqa/code/29 + + + 2015-08-29 + 42187 + ROANNE + 4 + 4 + 1 + 2 + + Samedi 29 août : la qualité de l'air sera médiocre. Les indices prévus sont majoritairement égaux à 6. Le polluant déterminant cet indice est l'ozone. Les prévisions de trafic routier important et la situation météorologique favoriseront le transport et la production d'ozone dans toute la vallée du Rhône ainsi que sur les vallées alpines. + http://www.lcsqa.org/aasqa/code/29 + + + 2015-08-29 + 26362 + VALENCE + 6 + 6 + 1 + 3 + + Samedi 29 août : la qualité de l'air sera médiocre. Les indices prévus sont majoritairement égaux à 6. Le polluant déterminant cet indice est l'ozone. Les prévisions de trafic routier important et la situation météorologique favoriseront le transport et la production d'ozone dans toute la vallée du Rhône ainsi que sur les vallées alpines. + http://www.lcsqa.org/aasqa/code/36 + + + 2015-08-29 + 26281 + ROMANS-SUR-ISERE + 6 + 6 + 1 + 3 + + Samedi 29 août : la qualité de l'air sera médiocre. Les indices prévus sont majoritairement égaux à 6. Le polluant déterminant cet indice est l'ozone. Les prévisions de trafic routier important et la situation météorologique favoriseront le transport et la production d'ozone dans toute la vallée du Rhône ainsi que sur les vallées alpines. + http://www.lcsqa.org/aasqa/code/36 + + + 2015-08-29 + 59178 + DOUAI + 3 + 4 + 2 + + 1 + Agglomération de Douai + http://www.lcsqa.org/aasqa/code/06 + + + 2015-08-29 + 59392 + MAUBEUGE + 3 + + 1 + 2 + + Agglomération de Maubeuge + http://www.lcsqa.org/aasqa/code/06 + + + 2015-08-29 + 59606 + VALENCIENNES + 3 + 4 + 1 + 3 + 1 + Agglomération de Valenciennes + http://www.lcsqa.org/aasqa/code/06 + + + 2015-08-29 + 51108 + CHALONS-EN-CHAMPAGNE + 5 + 4 + 1 + 2 + 1 + + http://www.lcsqa.org/aasqa/code/14 + + + 2015-08-29 + 08105 + CHARLEVILLE-MEZIERES + 5 + 4 + 1 + 2 + 1 + + http://www.lcsqa.org/aasqa/code/14 + + + 2015-08-29 + 51454 + REIMS + 5 + 4 + 2 + 2 + 1 + + http://www.lcsqa.org/aasqa/code/14 + + + 2015-08-29 + 52448 + SAINT-DIZIER + 5 + 5 + 1 + 2 + 1 + + http://www.lcsqa.org/aasqa/code/14 + + + 2015-08-29 + 10387 + TROYES + 5 + 5 + 1 + 2 + 1 + + http://www.lcsqa.org/aasqa/code/14 + + + 2015-08-29 + 73065 + CHAMBERY + 6 + 6 + 1 + 3 + + Samedi 29 août : la qualité de l'air sera médiocre. Les indices prévus sont majoritairement égaux à 6. Le polluant déterminant cet indice est l'ozone. Les prévisions de trafic routier important et la situation météorologique favoriseront le transport et la production d'ozone dans toute la vallée du Rhône ainsi que sur les vallées alpines. + http://www.lcsqa.org/aasqa/code/33 + + + 2015-08-29 + 73248 + SAINT-JEAN-DE-MAURIENNE + 5 + 5 + 1 + 3 + 2 + Samedi 29 août : la qualité de l'air sera médiocre. Les indices prévus sont majoritairement égaux à 6. Le polluant déterminant cet indice est l'ozone. Les prévisions de trafic routier important et la situation météorologique favoriseront le transport et la production d'ozone dans toute la vallée du Rhône ainsi que sur les vallées alpines. + http://www.lcsqa.org/aasqa/code/33 + + + 2015-08-29 + 74056 + CHAMONIX-MONT-BLANC + 5 + 5 + 2 + 3 + + Samedi 29 août : la qualité de l'air sera médiocre. Les indices prévus sont majoritairement égaux à 6. Le polluant déterminant cet indice est l'ozone. Les prévisions de trafic routier important et la situation météorologique favoriseront le transport et la production d'ozone dans toute la vallée du Rhône ainsi que sur les vallées alpines. + http://www.lcsqa.org/aasqa/code/33 + + + 2015-08-29 + 74010 + ANNECY + 6 + 6 + 2 + 3 + + Samedi 29 août : la qualité de l'air sera médiocre. Les indices prévus sont majoritairement égaux à 6. Le polluant déterminant cet indice est l'ozone. Les prévisions de trafic routier important et la situation météorologique favoriseront le transport et la production d'ozone dans toute la vallée du Rhône ainsi que sur les vallées alpines. + http://www.lcsqa.org/aasqa/code/33 + + + 2015-08-29 + 73011 + ALBERTVILLE + 6 + 6 + 1 + 4 + + Samedi 29 août : la qualité de l'air sera médiocre. Les indices prévus sont majoritairement égaux à 6. Le polluant déterminant cet indice est l'ozone. Les prévisions de trafic routier important et la situation météorologique favoriseront le transport et la production d'ozone dans toute la vallée du Rhône ainsi que sur les vallées alpines. + http://www.lcsqa.org/aasqa/code/33 + + + 2015-08-29 + 01053 + BOURG-EN-BRESSE + 6 + 6 + 2 + 3 + + Samedi 29 août : la qualité de l'air sera médiocre. Les indices prévus sont majoritairement égaux à 6. Le polluant déterminant cet indice est l'ozone. Les prévisions de trafic routier important et la situation météorologique favoriseront le transport et la production d'ozone dans toute la vallée du Rhône ainsi que sur les vallées alpines. + http://www.lcsqa.org/aasqa/code/33 + + + 2015-08-29 + 74012 + ANNEMASSE + 7 + 7 + 1 + 3 + + Samedi 29 août : la qualité de l'air sera médiocre. Les indices prévus sont majoritairement égaux à 6. Le polluant déterminant cet indice est l'ozone. Les prévisions de trafic routier important et la situation météorologique favoriseront le transport et la production d'ozone dans toute la vallée du Rhône ainsi que sur les vallées alpines. + http://www.lcsqa.org/aasqa/code/33 + + + 2015-08-29 + 74208 + PASSY + 5 + 5 + 1 + 2 + + Samedi 29 août : la qualité de l'air sera médiocre. Les indices prévus sont majoritairement égaux à 6. Le polluant déterminant cet indice est l'ozone. Les prévisions de trafic routier important et la situation météorologique favoriseront le transport et la production d'ozone dans toute la vallée du Rhône ainsi que sur les vallées alpines. + http://www.lcsqa.org/aasqa/code/33 + + + 2015-08-29 + 59017 + ARMENTIERES + 3 + 4 + 2 + 2 + + + http://www.lcsqa.org/aasqa/code/11 + + + 2015-08-29 + 59350 + LILLE + 3 + 4 + 1 + 3 + 1 + L'indice ATMO sur la Metropole lilloise. + http://www.lcsqa.org/aasqa/code/11 + + + 2015-08-29 + 62160 + BOULOGNE-SUR-MER + 3 + 4 + 1 + 2 + + Agglomération de Boulogne-sur-Mer + http://www.lcsqa.org/aasqa/code/10 + + + 2015-08-29 + 62193 + CALAIS + 3 + 4 + 1 + 2 + 1 + Agglomération de Calais + http://www.lcsqa.org/aasqa/code/10 + + + 2015-08-29 + 59183 + DUNKERQUE + 3 + 4 + 1 + 2 + 1 + Agglomération de Dunkerque + http://www.lcsqa.org/aasqa/code/10 + + + 2015-08-29 + 62765 + SAINT-OMER + 3 + 4 + 2 + 2 + + + http://www.lcsqa.org/aasqa/code/10 + + + 2015-08-29 + 54395 + NANCY + 5 + 5 + 2 + 2 + 1 + + http://www.lcsqa.org/aasqa/code/30 + + + 2015-08-29 + 57463 + METZ + 5 + 4 + 1 + 3 + 1 + + http://www.lcsqa.org/aasqa/code/01 + + + 2015-08-29 + 57672 + THIONVILLE + 4 + 5 + 1 + + 1 + + http://www.lcsqa.org/aasqa/code/01 + + + 2015-08-29 + 57227 + FORBACH + 5 + 4 + 1 + 3 + 1 + + http://www.lcsqa.org/aasqa/code/22 + + + 2015-08-29 + 62041 + ARRAS + 3 + 4 + 2 + 2 + + + http://www.lcsqa.org/aasqa/code/28 + + + 2015-08-29 + 62119 + BETHUNE + 3 + 4 + 1 + 2 + + Agglomération de Béthune + http://www.lcsqa.org/aasqa/code/28 + + + 2015-08-29 + 62498 + LENS + 3 + 4 + 2 + + 1 + + http://www.lcsqa.org/aasqa/code/28 + + + 2015-08-29 + 38544 + VIENNE + 6 + 6 + 2 + 3 + + Samedi 29 août : la qualité de l'air sera médiocre. Les indices prévus sont majoritairement égaux à 6. Le polluant déterminant cet indice est l'ozone. Les prévisions de trafic routier important et la situation météorologique favoriseront le transport et la production d'ozone dans toute la vallée du Rhône ainsi que sur les vallées alpines. + http://www.lcsqa.org/aasqa/code/27 + + + 2015-08-29 + 38053 + BOURGOIN-JALLIEU + 6 + 6 + 1 + 3 + + Samedi 29 août : la qualité de l'air sera médiocre. Les indices prévus sont majoritairement égaux à 6. Le polluant déterminant cet indice est l'ozone. Les prévisions de trafic routier important et la situation météorologique favoriseront le transport et la production d'ozone dans toute la vallée du Rhône ainsi que sur les vallées alpines. + http://www.lcsqa.org/aasqa/code/27 + + + 2015-08-29 + 69123 + LYON + 6 + 6 + 2 + 3 + 1 + Samedi 29 août : la qualité de l'air sera médiocre. Les indices prévus sont majoritairement égaux à 6. Le polluant déterminant cet indice est l'ozone. Les prévisions de trafic routier important et la situation météorologique favoriseront le transport et la production d'ozone dans toute la vallée du Rhône ainsi que sur les vallées alpines. + http://www.lcsqa.org/aasqa/code/20 + + + 2015-08-29 + 20004 + AJACCIO + 5 + 5 + 2 + 3 + 1 + + http://www.lcsqa.org/aasqa/code/41 + + + 2015-08-29 + 20033 + BASTIA + 5 + 5 + 1 + 3 + + + http://www.lcsqa.org/aasqa/code/41 + + + 2015-08-29 + 20341 + VENACO + 5 + 5 + 1 + 2 + + + http://www.lcsqa.org/aasqa/code/41 + + + 2015-08-29 + 80021 + AMIENS + 4 + 4 + 1 + 2 + + + http://www.lcsqa.org/aasqa/code/18 + + + 2015-08-29 + 60175 + CREIL + 4 + 3 + 1 + 2 + + + http://www.lcsqa.org/aasqa/code/18 + + + 2015-08-29 + 02691 + SAINT-QUENTIN + 4 + 4 + 1 + 2 + + + http://www.lcsqa.org/aasqa/code/18 + + + 2015-08-29 + 30189 + NIMES + 4 + 4 + 1 + 3 + + + http://www.lcsqa.org/aasqa/code/08 + + + 2015-08-29 + 66136 + PERPIGNAN + 4 + 4 + 1 + 4 + + + http://www.lcsqa.org/aasqa/code/08 + + + 2015-08-29 + 34172 + MONTPELLIER + 4 + 4 + 1 + 3 + + + http://www.lcsqa.org/aasqa/code/08 + + + 2015-08-29 + 34003 + AGDE + 4 + 4 + 1 + + + + http://www.lcsqa.org/aasqa/code/08 + + + 2015-08-29 + 34032 + BEZIERS + 4 + 4 + + + + + http://www.lcsqa.org/aasqa/code/08 + + + 2015-08-29 + 30278 + SAINT-LAURENT-DES-ARBRES + 7 + 7 + 1 + 2 + 1 + + http://www.lcsqa.org/aasqa/code/08 + + + 2015-08-29 + 66130 + OSSEJA + 4 + 4 + + + + + http://www.lcsqa.org/aasqa/code/08 + + + 2015-08-29 + 34107 + FRAISSE-SUR-AGOUT + 4 + 4 + + + + + http://www.lcsqa.org/aasqa/code/08 + + + 2015-08-29 + 30007 + ALES + 5 + 5 + + + + + http://www.lcsqa.org/aasqa/code/08 + + + 2015-08-29 + 31060 + BELESTA-EN-LAURAGAIS + 4 + 4 + + + + + http://www.lcsqa.org/aasqa/code/08 + + + 2015-08-29 + 97407 + PORT + 1 + + + + 1 + IQA Zone Le Port_Cambaie + http://www.lcsqa.org/aasqa/code/38 + + + 2015-08-29 + 97411 + SAINT-DENIS + 3 + + 1 + 3 + 1 + Agglomération de St Denis + http://www.lcsqa.org/aasqa/code/38 + + + 2015-08-29 + 97416 + SAINT-PIERRE + 4 + 3 + 1 + 4 + 1 + Agglomération de St Pierre_Le Tampon + http://www.lcsqa.org/aasqa/code/38 + + diff --git a/infoPollen.sh b/infoPollen.sh new file mode 100755 index 0000000..52c6a17 --- /dev/null +++ b/infoPollen.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +#value=`curl http://www.pollens.fr/docs/vigilance.html|grep valable|awk -F- '{print $2}' |awk -F"<" '{print $1}'| sed 's/ /_/g'` + +mkdir /tmp/vigilance; +cd /tmp/vigilance/; +rm *; +wget -nd -r -P . http://www.pollens.fr/docs/vigilance.html; +wget "http://internationalragweedsociety.org/vigilance/d 56.gif"; +wget "http://internationalragweedsociety.org/vigilance/d 35.gif"; +wget "http://internationalragweedsociety.org/vigilance/d 44.gif"; +lynx --dump vigilance.html | mutt -s "Alerte pollens" -a Departements_de_France-simple.png "d 56.gif" "d 35.gif" "d 44.gif" -- jerome.delacotte@gmail.com diff --git a/infotrafic.sh b/infotrafic.sh new file mode 100755 index 0000000..89d055b --- /dev/null +++ b/infotrafic.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +rm *obstacles* >/dev/null +date="$(date +%d-%m-%Y)" + +value=`wget "http://www.infotrafic.com/route.php?region=Ouest&link=obstacles.php" 2>/dev/null >/dev/null;lynx --dump "route.php?region=Ouest&link=obstacles.php"|grep "$date"| egrep "D8|D138|D149|D764|N166"|grep -v "ment termin"|awk -F "" '{print $2 $3}'|awk -F "" '{print $1}'| sed 's/ /_/g'` +#value=`wget "http://www.infotrafic.com/route.php?region=Ouest&link=obstacles.php" 2>/dev/null >/dev/null;cat "route.php?region=Ouest&link=obstacles.php"|grep N137|grep -v "ment termin"|awk -F "" '{print $2 $3}'|awk -F "" '{print $1}'| sed 's/ /_/g'` +echo $value +if [ -n "$value" ]; +then + json="http://localhost:81/json.htm?type=command¶m=udevice&idx=164&nvalue=4&svalue=$value" + echo "$json" + curl -i -H "Accept: application/json" $json + exit 1 +else + json="http://localhost:81/json.htm?type=command¶m=udevice&idx=164&nvalue=1&svalue=Trafic_sans_probleme" + #echo "HUM " $json >>/var/log/syslog + curl -s -i -H "Accept: application/json" $json + exit 1 +fi + diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..aeadaee --- /dev/null +++ b/install.sh @@ -0,0 +1,556 @@ +#!/usr/bin/env bash +# Domoticz: Open Source Home Automation System +# (c) 2012, 2016 by GizMoCuz +# Big thanks to Jacob Salmela! (This is based on the excelent Pi-Hole install script ;) +# http://www.domoticz.com +# Installs Domoticz +# +# Domoticz is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. + +# Donations are welcome via the website or application +# +# Install with this command (from your Pi): +# +# curl -L install.domoticz.com | bash + +set -e +######## VARIABLES ######### +setupVars=/etc/domoticz/setupVars.conf + +useUpdateVars=false + +Dest_folder="" +IPv4_address="" +Enable_http=true +Enable_https=true +HTTP_port="8080" +HTTPS_port="443" +Current_user="" + +lowercase(){ + echo "$1" | sed "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/" +} + +OS=`lowercase \`uname -s\`` +MACH=`uname -m` +if [ ${MACH} = "armv6l" ] +then + MACH="armv7l" +fi + +# Find the rows and columns will default to 80x24 is it can not be detected +screen_size=$(stty size 2>/dev/null || echo 24 80) +rows=$(echo $screen_size | awk '{print $1}') +columns=$(echo $screen_size | awk '{print $2}') + +# Divide by two so the dialogs take up half of the screen, which looks nice. +r=$(( rows / 2 )) +c=$(( columns / 2 )) +# Unless the screen is tiny +r=$(( r < 20 ? 20 : r )) +c=$(( c < 70 ? 70 : c )) + +######## Undocumented Flags. Shhh ######## +skipSpaceCheck=false +reconfigure=false + +######## FIRST CHECK ######## +# Must be root to install +echo ":::" +if [[ ${EUID} -eq 0 ]]; then + echo "::: You are root." +else + echo "::: Script called with non-root privileges. The Domoticz installs server packages and configures" + echo "::: system networking, it requires elevated rights. Please check the contents of the script for" + echo "::: any concerns with this requirement. Please be sure to download this script from a trusted source." + echo ":::" + echo "::: Detecting the presence of the sudo utility for continuation of this install..." + + if [ -x "$(command -v sudo)" ]; then + echo "::: Utility sudo located." + exec curl -sSL https://install.domoticz.com | sudo bash "$@" + exit $? + else + echo "::: sudo is needed for the Web interface to run domoticz commands. Please run this script as root and it will be automatically installed." + exit 1 + fi +fi + +# Compatibility + +if [ -x "$(command -v apt-get)" ]; then + #Debian Family + ############################################# + PKG_MANAGER="apt-get" + PKG_CACHE="/var/lib/apt/lists/" + UPDATE_PKG_CACHE="${PKG_MANAGER} update" + PKG_UPDATE="${PKG_MANAGER} upgrade" + PKG_INSTALL="${PKG_MANAGER} --yes --fix-missing install" + # grep -c will return 1 retVal on 0 matches, block this throwing the set -e with an OR TRUE + PKG_COUNT="${PKG_MANAGER} -s -o Debug::NoLocking=true upgrade | grep -c ^Inst || true" + INSTALLER_DEPS=( apt-utils whiptail git) + domoticz_DEPS=( curl unzip wget sudo cron libudev-dev) + + DEBIAN_ID=$(grep -oP '(?<=^ID=).+' /etc/*-release | tr -d '"') + DEBIAN_VERSION=$(grep -oP '(?<=^VERSION_ID=).+' /etc/*-release | tr -d '"') + + if test ${DEBIAN_VERSION} -lt 10 + then + domoticz_DEPS=( ${domoticz_DEPS[@]} libcurl3 ) + else + domoticz_DEPS=( ${domoticz_DEPS[@]} libcurl4 libusb-0.1) + fi; + + package_check_install() { + dpkg-query -W -f='${Status}' "${1}" 2>/dev/null | grep -c "ok installed" || ${PKG_INSTALL} "${1}" + } +elif [ -x "$(command -v rpm)" ]; then + # Fedora Family + if [ -x "$(command -v dnf)" ]; then + PKG_MANAGER="dnf" + else + PKG_MANAGER="yum" + fi + PKG_CACHE="/var/cache/${PKG_MANAGER}" + UPDATE_PKG_CACHE="${PKG_MANAGER} check-update" + PKG_UPDATE="${PKG_MANAGER} update -y" + PKG_INSTALL="${PKG_MANAGER} install -y" + PKG_COUNT="${PKG_MANAGER} check-update | egrep '(.i686|.x86|.noarch|.arm|.src)' | wc -l" + INSTALLER_DEPS=( procps-ng newt git ) + domoticz_DEPS=( curl libcurl4 unzip wget findutils cronie sudo domoticz_DEP) + if grep -q 'Fedora' /etc/redhat-release; then + remove_deps=(epel-release); + domoticz_DEPS=( ${domoticz_DEPS[@]/$remove_deps} ); + fi + package_check_install() { + rpm -qa | grep ^"${1}"- > /dev/null || ${PKG_INSTALL} "${1}" + } +else + echo "OS distribution not supported" + exit +fi + +####### FUNCTIONS ########## +spinner() { + local pid=$1 + local delay=0.50 + local spinstr='/-\|' + while [ "$(ps a | awk '{print $1}' | grep "${pid}")" ]; do + local temp=${spinstr#?} + printf " [%c] " "${spinstr}" + local spinstr=${temp}${spinstr%"$temp"} + sleep ${delay} + printf "\b\b\b\b\b\b" + done + printf " \b\b\b\b" +} + +find_current_user() { + # Find current user + Current_user=${SUDO_USER:-$USER} + echo "::: Current User: ${Current_user}" +} + +find_IPv4_information() { + # Find IP used to route to outside world + IPv4dev=$(ip route get 8.8.8.8 | awk '{for(i=1;i<=NF;i++)if($i~/dev/)print $(i+1)}') + IPv4_address=$(ip -o -f inet addr show dev "$IPv4dev" | awk '{print $4}' | awk 'END {print}') + IPv4gw=$(ip route get 8.8.8.8 | awk '{print $3}') +} + +welcomeDialogs() { + # Display the welcome dialog + whiptail --msgbox --backtitle "Welcome" --title "Domoticz automated installer" "\n\nThis installer will transform your device into a Home Automation System!\n\n +Domoticz is free, but powered by your donations at: http://www.domoticz.com\n\n +Domoticz is a SERVER so it needs a STATIC IP ADDRESS to function properly. + " ${r} ${c} +} + +displayFinalMessage() { + # Final completion message to user + whiptail --msgbox --backtitle "Ready..." --title "Installation Complete!" "Point your browser to either: + +HTTP: ${IPv4_address%/*}:${HTTP_port%/*} +HTTPS: ${IPv4_address%/*}:${HTTPS_port} + +Wiki: https://www.domoticz.com/wiki +Forum: https://www.domoticz.com/forum + +The install log is in /etc/domoticz." ${r} ${c} +} + +verifyFreeDiskSpace() { + + # 50MB is the minimum space needed + # - Fourdee: Local ensures the variable is only created, and accessible within this function/void. Generally considered a "good" coding practice for non-global variables. + echo "::: Verifying free disk space..." + local required_free_kilobytes=51200 + local existing_free_kilobytes=$(df -Pk | grep -m1 '\/$' | awk '{print $4}') + + # - Unknown free disk space , not a integer + if ! [[ "${existing_free_kilobytes}" =~ ^([0-9])+$ ]]; then + echo "::: Unknown free disk space!" + echo "::: We were unable to determine available free disk space on this system." + echo "::: You may override this check and force the installation, however, it is not recommended" + echo "::: To do so, pass the argument '--i_do_not_follow_recommendations' to the install script" + echo "::: eg. curl -L https://install.domoticz.com | bash /dev/stdin --i_do_not_follow_recommendations" + exit 1 + # - Insufficient free disk space + elif [[ ${existing_free_kilobytes} -lt ${required_free_kilobytes} ]]; then + echo "::: Insufficient Disk Space!" + echo "::: Your system appears to be low on disk space. Domoticz recommends a minimum of $required_free_kilobytes KiloBytes." + echo "::: You only have ${existing_free_kilobytes} KiloBytes free." + echo "::: If this is a new install you may need to expand your disk." + echo "::: Try running 'sudo raspi-config', and choose the 'expand file system option'" + echo "::: After rebooting, run this installation again. (curl -L https://install.domoticz.com | bash)" + + echo "Insufficient free space, exiting..." + exit 1 + + fi + +} + +chooseServices() { + Enable_http=false; + Enable_https=false; + # Let use enable HTTP and/or HTTPS + cmd=(whiptail --separate-output --checklist "Select Services (press space to select)" ${r} ${c} 2) + options=(HTTP "Enables HTTP access" on + HTTPS "Enabled HTTPS access" on) + choices=$("${cmd[@]}" "${options[@]}" 2>&1 >/dev/tty) + if [[ $? = 0 ]];then + for choice in ${choices} + do + case ${choice} in + HTTP ) Enable_http=true;; + HTTPS ) Enable_https=true;; + esac + done + if [ ! ${Enable_http} ] && [ ! ${Enable_https} ]; then + echo "::: Cannot continue, neither HTTP or HTTPS selected" + echo "::: Exiting" + exit 1 + fi + else + echo "::: Cancel selected. Exiting..." + exit 1 + fi + # Configure the port(s) + if [ "$Enable_http" = true ] ; then + HTTP_port=$(whiptail --inputbox "HTTP Port number:" ${r} ${c} ${HTTP_port} --title "Configure HTTP" 3>&1 1>&2 2>&3) + exitstatus=$? + if [ $exitstatus = 0 ]; then + echo "HTTP Port: " $HTTP_port + else + echo "::: Cancel selected. Exiting..." + exit 1 + fi + fi + if [ "$Enable_https" = true ] ; then + HTTPS_port=$(whiptail --inputbox "HTTPS Port number:" ${r} ${c} ${HTTPS_port} --title "Configure HTTPS" 3>&1 1>&2 2>&3) + exitstatus=$? + if [ $exitstatus = 0 ]; then + echo "HTTPS Port: " $HTTPS_port + else + echo "::: Cancel selected. Exiting..." + exit 1 + fi + fi +} + +chooseDestinationFolder() { + Dest_folder=$(whiptail --inputbox "Installation Folder:" ${r} ${c} ${Dest_folder} --title "Destination" 3>&1 1>&2 2>&3) + exitstatus=$? + if [ $exitstatus = 0 ]; then + echo ":::" + else + echo "::: Cancel selected. Exiting..." + exit 1 + fi +} + +stop_service() { + # Stop service passed in as argument. + echo ":::" + echo -n "::: Stopping ${1} service..." + if [ -x "$(command -v service)" ]; then + service "${1}" stop &> /dev/null & spinner $! || true + fi + echo " done." +} + +start_service() { + # Start/Restart service passed in as argument + # This should not fail, it's an error if it does + echo ":::" + echo -n "::: Starting ${1} service..." + if [ -x "$(command -v service)" ]; then + service "${1}" restart &> /dev/null & spinner $! + fi + echo " done." +} + +enable_service() { + # Enable service so that it will start with next reboot + echo ":::" + echo -n "::: Enabling ${1} service to start on reboot..." + if [ -x "$(command -v service)" ]; then + update-rc.d "${1}" defaults &> /dev/null & spinner $! + fi + echo " done." +} + +update_package_cache() { + #Running apt-get update/upgrade with minimal output can cause some issues with + #requiring user input (e.g password for phpmyadmin see #218) + + #Check to see if apt-get update has already been run today + #it needs to have been run at least once on new installs! + timestamp=$(stat -c %Y ${PKG_CACHE}) + timestampAsDate=$(date -d @"${timestamp}" "+%b %e") + today=$(date "+%b %e") + + if [ ! "${today}" == "${timestampAsDate}" ]; then + #update package lists + echo ":::" + echo -n "::: ${PKG_MANAGER} update has not been run today. Running now..." + ${UPDATE_PKG_CACHE} &> /dev/null & spinner $! + echo " done!" + fi +} + +notify_package_updates_available() { + # Let user know if they have outdated packages on their system and + # advise them to run a package update at soonest possible. + echo ":::" + echo -n "::: Checking ${PKG_MANAGER} for upgraded packages...." + updatesToInstall=$(eval "${PKG_COUNT}") + echo " done!" + echo ":::" + if [[ ${updatesToInstall} -eq "0" ]]; then + echo "::: Your system is up to date! Continuing with Domoticz installation..." + else + echo "::: There are ${updatesToInstall} updates available for your system!" + echo "::: We recommend you run '${PKG_UPDATE}' after installing Domoticz! " + echo ":::" + fi +} + +install_dependent_packages() { + # Install packages passed in via argument array + # No spinner - conflicts with set -e + declare -a argArray1=("${!1}") + + for i in "${argArray1[@]}"; do + echo -n "::: Checking for $i..." + package_check_install "${i}" &> /dev/null + echo " installed!" + done +} + +finalExports() { + #If it already exists, lets overwrite it with the new values. + if [[ -f ${setupVars} ]]; then + rm ${setupVars} + fi + { + echo "Dest_folder=${Dest_folder}" + echo "Enable_http=${Enable_http}" + echo "HTTP_port=${HTTP_port}" + echo "Enable_https=${Enable_https}" + echo "HTTPS_port=${HTTPS_port}" + }>> "${setupVars}" +} + +downloadDomoticzWeb() { + echo "::: Destination folder=${Dest_folder}" + if [[ ! -e $Dest_folder ]]; then + echo "::: Creating ${Dest_folder}" + mkdir $Dest_folder + chown "${Current_user}":"${Current_user}" $Dest_folder + fi + cd $Dest_folder + wget -O domoticz_release.tgz "http://www.domoticz.com/download.php?channel=release&type=release&system=${OS}&machine=${MACH}" + echo "::: Unpacking Domoticz..." + tar xvfz domoticz_release.tgz + rm domoticz_release.tgz + Database_file="${Dest_folder}/domoticz.db" + if [ ! -f $Database_file ]; then + echo "Creating database..." + touch $Database_file + chmod 644 $Database_file + chown "${Current_user}":"${Current_user}" $Database_file + fi +} + +makeStartupScript() { + cp "${Dest_folder}/domoticz.sh" /tmp/domoticz_tmp_ss1 + + #configure the script + cat /tmp/domoticz_tmp_ss1 | sed -e "s/USERNAME=pi/USERNAME=${Current_user}/" > /tmp/domoticz_tmp_ss2 + rm /tmp/domoticz_tmp_ss1 + + local http_port="${HTTP_port}" + local https_port="${HTTPS_port}" + if [ "$Enable_http" = false ] ; then + http_port="0" + fi + if [ "$Enable_https" = false ] ; then + https_port="0" + fi + + cat /tmp/domoticz_tmp_ss2 | sed -e "s/-www 8080/-www ${http_port}/" > /tmp/domoticz_tmp_ss1 + rm /tmp/domoticz_tmp_ss2 + cat /tmp/domoticz_tmp_ss1 | sed -e "s/-sslwww 443/-sslwww ${https_port}/" > /tmp/domoticz_tmp_ss2 + rm /tmp/domoticz_tmp_ss1 + cat /tmp/domoticz_tmp_ss2 | sed -e "s%/home/\$USERNAME/domoticz%${Dest_folder}%" > /tmp/domoticz_tmp_ss1 + rm /tmp/domoticz_tmp_ss2 + + mv /tmp/domoticz_tmp_ss1 /etc/init.d/domoticz.sh + chmod +x /etc/init.d/domoticz.sh + update-rc.d domoticz.sh defaults +} + +installdomoticz() { + # Install base files + downloadDomoticzWeb + makeStartupScript + finalExports +} + +updatedomoticz() { + # Source ${setupVars} for use in the rest of the functions. + . ${setupVars} + # Install base files + downloadDomoticzWeb +} + +update_dialogs() { + # reconfigure + if [ "${reconfigure}" = true ]; then + opt1a="Repair" + opt1b="This will retain existing settings" + strAdd="You will remain on the same version" + else + opt1a="Update" + opt1b="This will retain existing settings." + strAdd="You will be updated to the latest version." + fi + opt2a="Reconfigure" + opt2b="This will allow you to enter new settings" + + UpdateCmd=$(whiptail --title "Existing Install Detected!" --menu "\n\nWe have detected an existing install.\n\nPlease choose from the following options: \n($strAdd)" ${r} ${c} 2 \ + "${opt1a}" "${opt1b}" \ + "${opt2a}" "${opt2b}" 3>&2 2>&1 1>&3) + + if [[ $? = 0 ]];then + case ${UpdateCmd} in + ${opt1a}) + echo "::: ${opt1a} option selected." + useUpdateVars=true + ;; + ${opt2a}) + echo "::: ${opt2a} option selected" + useUpdateVars=false + ;; + esac + else + echo "::: Cancel selected. Exiting..." + exit 1 + fi + +} + +install_packages() { + # Update package cache + update_package_cache + + # Notify user of package availability + notify_package_updates_available + + # Install packages used by this installation script + install_dependent_packages INSTALLER_DEPS[@] + + # Install packages used by the Domoticz + install_dependent_packages domoticz_DEPS[@] +} + +main() { +# Check arguments for the undocumented flags + for var in "$@"; do + case "$var" in + "--reconfigure" ) reconfigure=true;; + "--i_do_not_follow_recommendations" ) skipSpaceCheck=false;; + "--unattended" ) runUnattended=true;; + esac + done + + if [[ -f ${setupVars} ]]; then + if [[ "${runUnattended}" == true ]]; then + echo "::: --unattended passed to install script, no whiptail dialogs will be displayed" + useUpdateVars=true + else + update_dialogs + fi + fi + + # Start the installer + # Verify there is enough disk space for the install + if [[ "${skipSpaceCheck}" == true ]]; then + echo "::: --i_do_not_follow_recommendations passed to script, skipping free disk space verification!" + else + verifyFreeDiskSpace + fi + + install_packages + + if [[ "${reconfigure}" == true ]]; then + echo "::: --reconfigure passed to install script. Not downloading/updating local installation" + else + echo "::: Downloading Domoticz" + fi + + find_current_user + + Dest_folder="/home/${Current_user}/domoticz" + + find_IPv4_information + + if [[ ${useUpdateVars} == false ]]; then + # Display welcome dialogs + welcomeDialogs + # Create directory for Domoticz storage + mkdir -p /etc/domoticz/ + # Install and log everything to a file + chooseServices + chooseDestinationFolder + installdomoticz + else + updatedomoticz + fi + + if [[ "${useUpdateVars}" == false ]]; then + displayFinalMessage + fi + + echo "::: Restarting services..." + # Start services + enable_service domoticz.sh + start_service domoticz.sh + echo "::: done." + + echo ":::" + if [[ "${useUpdateVars}" == false ]]; then + echo "::: Installation Complete! Configure your browser to use the Domoticz using:" + echo "::: ${IPv4_address%/*}:${HTTP_port}" + echo "::: ${IPv4_address%/*}:${HTTPS_port}" + else + echo "::: Update complete!" + fi +} + +main "$@" diff --git a/launchSheepit.sh b/launchSheepit.sh new file mode 100755 index 0000000..d48b366 --- /dev/null +++ b/launchSheepit.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +java -jar Blender/sheepit-client-6.2020.0.jar -ui text -login Souti -password jefa6jyu & +cpulimit -e rend.exe -l 50 & diff --git a/livebox.php b/livebox.php new file mode 100755 index 0000000..636c346 --- /dev/null +++ b/livebox.php @@ -0,0 +1,133 @@ +"; +var_dump($json); +echo "";*/ + +if ($json['status'] != '') + { + die("Erreur lors de l'authentification: ".$json['status'].""); + } +if (isset($json['data']['contextID'])) + { + $access_token = $json['data']['contextID']; + } + +//recupération des infos de connexion +$headers = array("Content-Type: application/json","X-Context: ".$access_token); + +switch($_GET['action']){ + + case 'wifistate': + $response = httpQuery("http://".$myhost."/sysbus/NMC/Wifi:get","POST",'{"parameters":{}}',null,$headers,true); + //$json = sdk_json_decode($response); + echo $response; + break; + + case 'lanstate': + $response = httpQuery("http://".$myhost."/sysbus/NeMo/Intf/lan:getMIBs","POST",'{"parameters":{}}',null,$headers,true); + echo $response; + break; + + case 'dslstate': + $response = httpQuery("http://".$myhost."/sysbus/NeMo/Intf/dsl0:getDSLStats","POST",'{"parameters":{}}',null,$headers,true); + echo $response; + break; + + case 'users': + $response = httpQuery("http://".$myhost."/sysbus/UserManagement:getUsers","POST",'{"parameters":{}}',null,$headers,true); + echo $response; + break; + + case 'iplan': + $response = httpQuery("http://".$myhost."/sysbus/NeMo/Intf/lan:luckyAddrAddress","POST",'{"parameters":{}}',null,$headers,true); + echo $response; + break; + + case 'ipwan': + $response = httpQuery("http://".$myhost."/sysbus/NeMo/Intf/data:luckyAddrAddress","POST",'{"parameters":{}}',null,$headers,true); + echo $response; + break; + + case 'wanstate': + $response = httpQuery("http://".$myhost."/sysbus/NMC:getWANStatus","POST",'{"parameters":{}}',null,$headers,true); + echo $response; + break; + + case 'phonestate': + $response = httpQuery("http://".$myhost."/sysbus/VoiceService/VoiceApplication:listTrunks","POST",'{"parameters":{}}',null,$headers,true); + echo $response; + break; + + case 'tvstate': + $response = httpQuery("http://".$myhost."/sysbus/NMC/OrangeTV:getIPTVStatus","POST",'{"parameters":{}}',null,$headers,true); + echo $response; + break; + + case 'hosts': + $response = httpQuery("http://".$myhost."/sysbus/Hosts:getDevices","POST",'{"parameters":{}}',null,$headers,true); + echo $response; + break; + + case 'reboot': + $response = httpQuery("http://".$myhost."/sysbus/NMC:reboot","POST",'{"parameters":{}}',null,$headers,true); + echo $response; + break; + + case 'wifion': + $response = httpQuery("http://".$myhost."/sysbus/NMC/Wifi:set","POST",'{"parameters":{"Enable":true,"Status":true}}',null,$headers,true); + echo $response; + break; + + case 'wifioff': + $response = httpQuery("http://".$myhost."/sysbus/NMC/Wifi:set","POST",'{"parameters":{"Enable":false,"Status":false}}',null,$headers,true); + echo $response; + break; + + case 'mibs': + $response = httpQuery("http://".$myhost."/sysbus/NeMo/Intf/data:getMIBs","POST",'{"parameters":{}}',null,$headers,true); + echo $response; + break; + + case 'macoff': + $response = httpQuery("http://".$myhost."/sysbus/NeMo/Intf/wl0:setWLANConfig","POST",'{"parameters":{"mibs":{"wlanvap":{"wl0":{"MACFiltering":{"Mode":"Off"},"WPS":{"Enable":false}}}}}}',null,$headers,true); + echo $response; + break; + + case 'macon': + $response = httpQuery("http://".$myhost."/sysbus/NeMo/Intf/wl0:setWLANConfig","POST",'{"parameters":{"mibs":{"wlanvap":{"wl0":{"MACFiltering":{"Mode":"WhiteList"}}}}}}',null,$headers,true); + echo $response; + break; + + case 'dslinfo': + $response = httpQuery("http://".$myhost."/sysbus/NeMo/Intf/data:getMIBs","POST",'{"parameters":{"mibs":"dsl","flag":"","traverse":"down"}}',null,$headers,true); + echo $response; + break; + + default: + $result = '{"result":"Aucune action definie"}'; + echo $result; + break; +} + +/* +echo ""; +var_dump($json); +echo ""; +*/ + +//logout +$response = httpQuery("http://".$myhost."/logout","POST",null,null,true); + +?> + diff --git a/livebox.sh b/livebox.sh new file mode 100755 index 0000000..4dab90e --- /dev/null +++ b/livebox.sh @@ -0,0 +1,11 @@ +#!/bin/bash +clear +curl -o /tmp/context -X GET -i -H "Content-type: application/json" -c /tmp/cookies.txt "http://192.168.1.1/homeAuthentication.html?username=admin&password=HYJcanGE" +#curl -o /tmp/context -X POST -i -H "Content-type: application/json" -c /tmp/cookies.txt "http://192.168.1.1/authenticate?username=admin&password=HYJcanGE" +ID=$(tail -n1 /tmp/context | sed 's/{"status":0,"data":{"contextID":"//1'| sed 's/"}}//1') +curl -b /tmp/cookies.txt http://192.168.1.1/sysbus/Devices -o /tmp/getHosts.txt +#curl -b /tmp/cookies.txt -X POST -H 'Content-Type: application/json' -H 'X-Context: '$ID'' -d '{"parameters":{}}' http://192.168.1.1/sysbus/Devices -o /tmp/getHosts.txt +#curl -b /tmp/cookies.txt -X POST -H 'Content-Type: application/json' -H 'X-Context: '$ID'' -d '{"parameters":{}}' http://192.168.1.1/sysbus/Hosts:getDevices -o /tmp/getHosts.txt +curl -i -b /tmp/cookies.txt -X POST http://192.168.1.1/logout +rm /tmp/cookies.txt +rm /tmp/context diff --git a/livebox2.sh b/livebox2.sh new file mode 100755 index 0000000..2d42bf9 --- /dev/null +++ b/livebox2.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +########################################### + # Firmware Livebox 4 = 2.22.8 g0-f-sip-fr # +# Script mis a jour le 03/06/2017 # +########################################### + +#script source https://blog.tetsumaki.net/articles/2015/10/recuperation-dinformations-livebox-play.html + +############################# +# Déclaration des variables # +############################# +myLivebox=192.168.1.1 +myPassword=HYJcanGE + +#myBashDir=/home/pi/domoticz/scripts/sh/livebox/ +myBashDir=/tmp/ + +myOutput=$myBashDir/myOutput.txt +myCookies=$myBashDir/myCookies.txt + +######################################## +# Connexion et recuperation du cookies # +######################################## +curl -s -o "$myOutput" -X POST -c "$myCookies" -H 'Content-Type: application/x-sah-ws-4-call+json' -H 'Authorization: X-Sah-Login' -d "{\"service\":\"sah.Device.Information\",\"method\":\"createContext\",\"parameters\":{\"applicationName\":\"so_sdkut\",\"username\":\"admin\",\"password\":\"$myPassword\"}}" http://$myLivebox/ws > /dev/null + +################################################## +# Lecture du cookies pour utilisation ultérieure # +################################################## +myContextID=$(tail -n1 "$myOutput" | sed 's/{"status":0,"data":{"contextID":"//1'| sed 's/",//1' | sed 's/"groups":"http,admin//1' | sed 's/"}}//1') + +############################################################################################### +# Envoi des commandes pour récupérer les informations et écriture dans un fichier TXT séparé # +############################################################################################### +getDSLStats=`curl -s -b "$myCookies" -X POST -H 'Content-Type: application/x-sah-ws-4-call+json' -H "X-Context: $myContextID" -d "{\"service\":\"NeMo.Intf.dsl0\",\"method\":\"getDSLStats\",\"parameters\":{}}" http://$myLivebox/ws` +getMIBs=`curl -s -b "$myCookies" -X POST -H 'Content-Type: application/x-sah-ws-4-call+json' -H "X-Context: $myContextID" -d "{\"service\":\"NeMo.Intf.data\",\"method\":\"getMIBs\",\"parameters\":{}}" http://$myLivebox/ws` +getWanStatus=`curl -s -b "$myCookies" -X POST -H 'Content-Type: application/x-sah-ws-4-call+json' -H "X-Context: $myContextID" -d "{\"service\":\"NMC\",\"method\":\"getWANStatus\",\"parameters\":{}}" http://$myLivebox/ws` +getDeviceInfo=`curl -s -b "$myCookies" -X POST -H 'Content-Type: application/x-sah-ws-4-call+json' -H "X-Context: $myContextID" -d "{\"service\":\"DeviceInfo\",\"method\":\"get\",\"parameters\":{}}" http://$myLivebox/ws` +getDevices=`curl -s -b "$myCookies" -X POST -H 'Content-Type: application/x-sah-ws-4-call+json' -H "X-Context: $myContextID" -d "{\"service\":\"Devices\",\"method\":\"get\",\"parameters\":{}}" http://$myLivebox/ws` +#getDevices=`curl -s -b "$myCookies" -X POST -H 'Content-Type: application/json\' -H "X-Context: $myContextID" -d "{\"service\":\"Devices\",\"method\":\"get\",\"parameters\":{}}" http://$myLivebox/ws` + +echo $getDSLStats > $myBashDir/DSLStats.txt +echo $getMIBs > $myBashDir/MIBs.txt +echo $getWanStatus > $myBashDir/WanStatus.txt +echo $getDeviceInfo > $myBashDir/DeviceInfo.txt +echo $getDevices > $myBashDir/Devices.txt +####################################################### +# Deconnexion et suppression des fichiers temporaires # +####################################################### +curl -s -b "$myCookies" -X POST http://$myLivebox/logout +rm "$myCookies" "$myOutput" + + diff --git a/livebox_fibre.sh b/livebox_fibre.sh new file mode 100755 index 0000000..469e84c --- /dev/null +++ b/livebox_fibre.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +# Paramètres +LIVEBOX_IP="192.168.1.1" +USERNAME="admin" +PASSWORD="HYJcanGE" # Change avec ton vrai mot de passe +CURL_OPTS="-s" + +# 1️⃣ Authentification - obtenir le contextID +CONTEXT_ID=$(curl $CURL_OPTS -X POST "http://$LIVEBOX_IP/ws" \ + -H "Content-Type: application/x-sah-ws-4-call+json" \ + -H "Authorization: X-Sah-Login" \ + -d "{ + \"service\": \"sah.Device.Information\", + \"method\": \"createContext\", + \"parameters\": { + \"applicationName\": \"curl\", + \"username\": \"$USERNAME\", + \"password\": \"$PASSWORD\" + } + }" | jq -r '.data.contextID') + +if [ -z "$CONTEXT_ID" ] || [ "$CONTEXT_ID" == "null" ]; then + echo "❌ Erreur d'authentification" + exit 1 +fi + +# 2️⃣ Récupération de la liste des équipements connectés +DEVICE_LIST=$(curl $CURL_OPTS -X POST "http://$LIVEBOX_IP/ws" \ + -H "Content-Type: application/x-sah-ws-4-call+json" \ + -H "X-Context: $CONTEXT_ID" \ + -d '{ + "service": "NeMo.Intf.lan", + "method": "getMIBs", + "parameters": { + "mibs": "dhcp_leases" + } + }') + +# 3️⃣ Extraction et affichage propre +echo "📡 Appareils connectés :" +echo "$DEVICE_LIST" | jq -r '.data.dhcp_leases[] | "\(.IPAddress) - \(.HostName) - \(.MACAddress)"' + +# Optionnel : déconnexion propre (fermeture de la session) +curl $CURL_OPTS -X POST "http://$LIVEBOX_IP/ws" \ + -H "Content-Type: application/x-sah-ws-4-call+json" \ + -H "X-Context: $CONTEXT_ID" \ + -d '{ + "service": "sah.Device.Information", + "method": "releaseContext", + "parameters": {} + }' > /dev/null + + diff --git a/logrotate/domoticz b/logrotate/domoticz new file mode 100644 index 0000000..9995d82 --- /dev/null +++ b/logrotate/domoticz @@ -0,0 +1,14 @@ +/var/log/domoticz.log { + missingok + weekly + rotate 7 + compress + notifempty + postrotate + if [ -x /usr/sbin/invoke-rc.d ]; then \ + invoke-rc.d domoticz reload > /dev/null; \ + else \ + /etc/init.d/domoticz reload > /dev/null; \ + fi + endscript +} diff --git a/logwatch.sh b/logwatch.sh new file mode 100755 index 0000000..68042c7 --- /dev/null +++ b/logwatch.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +/usr/sbin/logwatch --detail high --format html >/tmp/logwatch.html; echo "Log watch" | /usr/bin/mutt -s "Rapport logwatch domoticz" -a /tmp/logwatch.html -- jerome.delacotte@gmail.com diff --git a/lua-sqlite3-0.4.1/ChangeLog b/lua-sqlite3-0.4.1/ChangeLog new file mode 100644 index 0000000..0b29130 --- /dev/null +++ b/lua-sqlite3-0.4.1/ChangeLog @@ -0,0 +1,78 @@ + +2006-05-11 Michael Roth + + Version 0.4.1 + * libluasqlite3.c: Fix to compile with MSVC6. + + +2006-05-09 Michael Roth + + Version 0.4 + + +2006-04-12 Michael Roth + + * Makefile.in, configure.ac, configure: Switched to gnu + autoconf framework. + + +2006-04-09 Michael Roth + + * Makefile (clean): Documentation will no longer vaporize. + * libluasqlite3-loader.lua.in: loadlib Fix for lua-5.1. + * exmaples/*: Search path fixes for lua-5.1 + + +2005-09-14 Michael Roth + + * sqlite3.lua (call_user_func): Fix for nil arguments in lua-5.1. + (stmt_class.first_cols): Dito but for return values. + * tests-sqlite3.lua (bug:test_nils): Testcase for nils in lua-5.1. + + +2005-06-15 Michael Roth + + Version 0.3: + * Documentation updates. + * examples/smart.lua: New. + * tests-sqlite3.lua: New test cases for parameter names without + leading dollar or colon sign. + New test cases for binding with name/value tables. + New test cases for stmt:parameter_names(). + * sqlite3.lua (stmt_class.prepare): Support for parameter names + without leading dollar or colon sign. + (stmt_class.bind) Support for binding with name/value tables. + (stmt_class.parameter_names) new. + + +2005-06-14 Michael Roth + + * sqlite3.lua (stmt_class.prepare): Auto parameter mapping. + * libluasqlite3.c (l_sqlite3_bind_parameter_name_x): new. + + +2005-06-03 Michael Roth + + * sqlite3.lua (db_class.set_busy_timeout & set_busy_handler): new. + (db_class.set_trace_handler): Fixed error handling. + (stmt_rows): Fixed autoclose and reset behaviour (Bug #1). + + +2005-06-02 Michael Roth + + * tests-sqlite3.lua: New test case for reported bugs. + (bug:test_1): Bug #1, bind()/first_cols() problem on empty tables. + + +2004-10-07 Michael Roth + + Version 0.2: + * Lua-Sqlite3 should now compile with older compilers. + * Requires the sqlite library version 3.0.7. + + +2004-09-14 Michael Roth + + Version 0.1 (alpha): + * This is the first public release of Lua-Sqlite3. + diff --git a/lua-sqlite3-0.4.1/LICENSE b/lua-sqlite3-0.4.1/LICENSE new file mode 100644 index 0000000..14bc4cc --- /dev/null +++ b/lua-sqlite3-0.4.1/LICENSE @@ -0,0 +1,32 @@ + +Lua-Sqlite3 License +------------------- + +Lua-Sqlite3 is written by Michael Roth and is +licensed under the terms of the MIT license reproduced below. + +======================================================================== + +Copyright (c) 2004, 2005, 2006 Michael Roth + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +======================================================================== + diff --git a/lua-sqlite3-0.4.1/Makefile.in b/lua-sqlite3-0.4.1/Makefile.in new file mode 100644 index 0000000..4185816 --- /dev/null +++ b/lua-sqlite3-0.4.1/Makefile.in @@ -0,0 +1,139 @@ + +prefix := @prefix@ + +exec_prefix := @exec_prefix@ + +bindir := @bindir@ +sbindir := @sbindir@ +libdir := @libdir@ +libexecdir := @libexecdir@ +mandir := @mandir@ + +luadir := @libdir@/lua + +install := install +install-data := $(install) -p -m 644 +install-prog := $(install) -p -m 755 +install-dirs := $(install) -d + +LUA := @LUA@ + +CC := @CC@ + +CFLAGS := @CFLAGS@ +LDFLAGS := @LDFLAGS@ + +LIBS := @LIBS@ + +COMPILE = $(CC) -c $(CFLAGS) -o $@ $< +LINK = $(CC) $(LDFLAGS) -o $@ $+ $(LIBS) +LINKSHARED = $(CC) -shared $(LDFLAGS) -o $@ $+ $(LIBS) + +DESTDIR = + +PACKAGE_NAME := lua-sqlite3 +PACKAGE_VERSION := 0.4.1 + +LUA_FILES := sqlite3.lua luasql-sqlite3.lua + +SOURCE_FILES := libluasqlite3.c + +DOC_FILES := documentation.html README LICENSE + +DIST_FILES := $(LUA_FILES) $(SOURCE_FILES) $(DOC_FILES) \ + Makefile.in lunit.lua tests-luasql.lua \ + tests-sqlite3.lua tests.lua \ + libluasqlite3-loader.lua.in ChangeLog \ + configure.ac configure + +DIST_DIR := $(PACKAGE_NAME)-$(PACKAGE_VERSION) + +CLEAN_FILES := libluasqlite3.o libluasqlite3.so \ + libluasqlite3-loader.lua libluasqlite3-loader.lua.install + +DESTDIR := + + +all: libluasqlite3.so libluasqlite3-loader.lua libluasqlite3-loader.lua.install + +install: all + $(install-dirs) $(DESTDIR)$(luadir) + $(install-data) $(LUA_FILES) libluasqlite3.so $(DESTDIR)$(luadir) + $(install-data) libluasqlite3-loader.lua.install $(DESTDIR)$(luadir)/libluasqlite3-loader.lua + +uninstall: + ( cd $(DESTDIR)$(luadir); rm -f $(LUA_FILES) libluasqlite3-loader.lua libluasqlite3.so ) + +clean: + rm -f $(CLEAN_FILES) + +allclean: clean distclean docsclean + +distdir: $(DIST_FILES) docs + rm -rf $(DIST_DIR) + mkdir $(DIST_DIR) $(DIST_DIR)/examples + cp -a -L $(DIST_FILES) $(DIST_DIR) + cp -a -L examples/*.lua $(DIST_DIR)/examples + find $(DIST_DIR) -perm +444 -exec chmod a+w {} \; + find $(DIST_DIR) -perm +222 -exec chmod a+r {} \; + find $(DIST_DIR) -perm +111 -exec chmod a+x {} \; + chmod -R a-st $(DIST_DIR) + chmod -R go-w $(DIST_DIR) + chmod 755 $(DIST_DIR) + touch distdir + +dist-tar: distdir + tar -c -f $(DIST_DIR).tar --owner=root --group=root $(DIST_DIR) + touch dist-tar + +dist-bz2: dist-tar + rm -f $(DIST_DIR).tar.gz + gzip -9 -c $(DIST_DIR).tar > $(DIST_DIR).tar.gz + touch dist-bz2 + +dist-gz: dist-tar + rm -f $(DIST_DIR).tar.bz2 + bzip2 -9 -c $(DIST_DIR).tar > $(DIST_DIR).tar.bz2 + touch dist-gz + +dist-zip: distdir + zip -rq $(DIST_DIR).zip $(DIST_DIR) + touch dist-zip + +dist: dist-bz2 dist-gz dist-zip + +distclean: + rm -rf $(DIST_DIR) + rm -f $(DIST_DIR).tar $(DIST_DIR).tar.gz $(DIST_DIR).tar.bz2 $(DIST_DIR).zip + rm -f distdir dist-tar dist-gz dist-bz2 dist-zip + +devel: + ./make-devel.sh +develclean: + rm -rf obj-5.0 obj-5.1 + +docs: documentation.html + +docsclean: + rm -f documentation.html + +check: all + $(LUA) tests.lua + +documentation.html: docs/doc.mrd makedoc.lua + $(LUA) makedoc.lua >documentation.html + +libluasqlite3.o: libluasqlite3.c + $(COMPILE) + +libluasqlite3.so: libluasqlite3.o + $(LINKSHARED) + +libluasqlite3-loader.lua.install: libluasqlite3-loader.lua.in + m4 -DSHARED_LIB_PATH=$(luadir) \ + < libluasqlite3-loader.lua.in > libluasqlite3-loader.lua.install + +libluasqlite3-loader.lua: libluasqlite3-loader.lua.in + m4 -DSHARED_LIB_PATH=$(shell pwd) \ + < libluasqlite3-loader.lua.in > libluasqlite3-loader.lua + diff --git a/lua-sqlite3-0.4.1/README b/lua-sqlite3-0.4.1/README new file mode 100644 index 0000000..72e6974 --- /dev/null +++ b/lua-sqlite3-0.4.1/README @@ -0,0 +1,19 @@ + +This is Lua-Sqlite3 release 0.4.1. + +Lua-Sqlite3 is a sqlite3 wrapper for lua. + +To learn more about lua-sqlite3 take a look in documentation.html. + +Edit Makefile.cfg to match your environment. + +Please note that this release is still alpha software. This mean that +there exists a chance that function signatures and behavour will change +in the future. + +If you have suggestions, questions or feature request please +feel free to contact me. + + +Michael Roth + diff --git a/lua-sqlite3-0.4.1/config.log b/lua-sqlite3-0.4.1/config.log new file mode 100644 index 0000000..33a6cd8 --- /dev/null +++ b/lua-sqlite3-0.4.1/config.log @@ -0,0 +1,457 @@ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by lua-sqlite3 configure 0.4, which was +generated by GNU Autoconf 2.59. Invocation command line was + + $ ./configure + +## --------- ## +## Platform. ## +## --------- ## + +hostname = domoticz +uname -m = armv7l +uname -r = 4.1.13-v7+ +uname -s = Linux +uname -v = #826 SMP PREEMPT Fri Nov 13 20:19:03 GMT 2015 + +/usr/bin/uname -p = unknown +/bin/uname -X = unknown + +/bin/arch = unknown +/usr/bin/arch -k = unknown +/usr/convex/getsysinfo = unknown +hostinfo = unknown +/bin/machine = unknown +/usr/bin/oslevel = unknown +/bin/universe = unknown + +PATH: /usr/local/sbin +PATH: /usr/local/bin +PATH: /usr/sbin +PATH: /usr/bin +PATH: /sbin +PATH: /bin + + +## ----------- ## +## Core tests. ## +## ----------- ## + +configure:1373: checking for gcc +configure:1389: found /usr/bin/gcc +configure:1399: result: gcc +configure:1643: checking for C compiler version +configure:1646: gcc --version &5 +gcc (Debian 4.6.3-14+rpi1) 4.6.3 +Copyright (C) 2011 Free Software Foundation, Inc. +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +configure:1649: $? = 0 +configure:1651: gcc -v &5 +Using built-in specs. +COLLECT_GCC=gcc +COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/4.6/lto-wrapper +Target: arm-linux-gnueabihf +Configured with: ../src/configure -v --with-pkgversion='Debian 4.6.3-14+rpi1' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --disable-sjlj-exceptions --with-arch=armv6 --with-fpu=vfp --with-float=hard --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf +Thread model: posix +gcc version 4.6.3 (Debian 4.6.3-14+rpi1) +configure:1654: $? = 0 +configure:1656: gcc -V &5 +gcc: error: unrecognized option '-V' +gcc: fatal error: no input files +compilation terminated. +configure:1659: $? = 4 +configure:1682: checking for C compiler default output file name +configure:1685: gcc conftest.c >&5 +configure:1688: $? = 0 +configure:1734: result: a.out +configure:1739: checking whether the C compiler works +configure:1745: ./a.out +configure:1748: $? = 0 +configure:1765: result: yes +configure:1772: checking whether we are cross compiling +configure:1774: result: no +configure:1777: checking for suffix of executables +configure:1779: gcc -o conftest conftest.c >&5 +configure:1782: $? = 0 +configure:1807: result: +configure:1813: checking for suffix of object files +configure:1834: gcc -c conftest.c >&5 +configure:1837: $? = 0 +configure:1859: result: o +configure:1863: checking whether we are using the GNU C compiler +configure:1887: gcc -c conftest.c >&5 +configure:1893: $? = 0 +configure:1897: test -z + || test ! -s conftest.err +configure:1900: $? = 0 +configure:1903: test -s conftest.o +configure:1906: $? = 0 +configure:1919: result: yes +configure:1925: checking whether gcc accepts -g +configure:1946: gcc -c -g conftest.c >&5 +configure:1952: $? = 0 +configure:1956: test -z + || test ! -s conftest.err +configure:1959: $? = 0 +configure:1962: test -s conftest.o +configure:1965: $? = 0 +configure:1976: result: yes +configure:1993: checking for gcc option to accept ANSI C +configure:2063: gcc -c -g -O2 conftest.c >&5 +configure:2069: $? = 0 +configure:2073: test -z + || test ! -s conftest.err +configure:2076: $? = 0 +configure:2079: test -s conftest.o +configure:2082: $? = 0 +configure:2100: result: none needed +configure:2118: gcc -c -g -O2 conftest.c >&5 +conftest.c:2:3: error: unknown type name 'choke' +conftest.c:2:3: error: expected '=', ',', ';', 'asm' or '__attribute__' at end of input +configure:2124: $? = 1 +configure: failed program was: +| #ifndef __cplusplus +| choke me +| #endif +configure:2263: checking how to run the C preprocessor +configure:2298: gcc -E conftest.c +configure:2304: $? = 0 +configure:2336: gcc -E conftest.c +conftest.c:9:28: fatal error: ac_nonexistent.h: No such file or directory +compilation terminated. +configure:2342: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| +| #define PACKAGE_NAME "lua-sqlite3" +| #define PACKAGE_TARNAME "lua-sqlite3" +| #define PACKAGE_VERSION "0.4" +| #define PACKAGE_STRING "lua-sqlite3 0.4" +| #define PACKAGE_BUGREPORT "mroth@nessie.de" +| /* end confdefs.h. */ +| #include +configure:2381: result: gcc -E +configure:2405: gcc -E conftest.c +configure:2411: $? = 0 +configure:2443: gcc -E conftest.c +conftest.c:9:28: fatal error: ac_nonexistent.h: No such file or directory +compilation terminated. +configure:2449: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| +| #define PACKAGE_NAME "lua-sqlite3" +| #define PACKAGE_TARNAME "lua-sqlite3" +| #define PACKAGE_VERSION "0.4" +| #define PACKAGE_STRING "lua-sqlite3 0.4" +| #define PACKAGE_BUGREPORT "mroth@nessie.de" +| /* end confdefs.h. */ +| #include +configure:2493: checking for egrep +configure:2503: result: grep -E +configure:2508: checking for ANSI C header files +configure:2533: gcc -c -g -O2 conftest.c >&5 +configure:2539: $? = 0 +configure:2543: test -z + || test ! -s conftest.err +configure:2546: $? = 0 +configure:2549: test -s conftest.o +configure:2552: $? = 0 +configure:2641: gcc -o conftest -g -O2 conftest.c >&5 +conftest.c: In function 'main': +conftest.c:26:7: warning: incompatible implicit declaration of built-in function 'exit' [enabled by default] +configure:2644: $? = 0 +configure:2646: ./conftest +configure:2649: $? = 0 +configure:2664: result: yes +configure:2688: checking for sys/types.h +configure:2704: gcc -c -g -O2 conftest.c >&5 +configure:2710: $? = 0 +configure:2714: test -z + || test ! -s conftest.err +configure:2717: $? = 0 +configure:2720: test -s conftest.o +configure:2723: $? = 0 +configure:2734: result: yes +configure:2688: checking for sys/stat.h +configure:2704: gcc -c -g -O2 conftest.c >&5 +configure:2710: $? = 0 +configure:2714: test -z + || test ! -s conftest.err +configure:2717: $? = 0 +configure:2720: test -s conftest.o +configure:2723: $? = 0 +configure:2734: result: yes +configure:2688: checking for stdlib.h +configure:2704: gcc -c -g -O2 conftest.c >&5 +configure:2710: $? = 0 +configure:2714: test -z + || test ! -s conftest.err +configure:2717: $? = 0 +configure:2720: test -s conftest.o +configure:2723: $? = 0 +configure:2734: result: yes +configure:2688: checking for string.h +configure:2704: gcc -c -g -O2 conftest.c >&5 +configure:2710: $? = 0 +configure:2714: test -z + || test ! -s conftest.err +configure:2717: $? = 0 +configure:2720: test -s conftest.o +configure:2723: $? = 0 +configure:2734: result: yes +configure:2688: checking for memory.h +configure:2704: gcc -c -g -O2 conftest.c >&5 +configure:2710: $? = 0 +configure:2714: test -z + || test ! -s conftest.err +configure:2717: $? = 0 +configure:2720: test -s conftest.o +configure:2723: $? = 0 +configure:2734: result: yes +configure:2688: checking for strings.h +configure:2704: gcc -c -g -O2 conftest.c >&5 +configure:2710: $? = 0 +configure:2714: test -z + || test ! -s conftest.err +configure:2717: $? = 0 +configure:2720: test -s conftest.o +configure:2723: $? = 0 +configure:2734: result: yes +configure:2688: checking for inttypes.h +configure:2704: gcc -c -g -O2 conftest.c >&5 +configure:2710: $? = 0 +configure:2714: test -z + || test ! -s conftest.err +configure:2717: $? = 0 +configure:2720: test -s conftest.o +configure:2723: $? = 0 +configure:2734: result: yes +configure:2688: checking for stdint.h +configure:2704: gcc -c -g -O2 conftest.c >&5 +configure:2710: $? = 0 +configure:2714: test -z + || test ! -s conftest.err +configure:2717: $? = 0 +configure:2720: test -s conftest.o +configure:2723: $? = 0 +configure:2734: result: yes +configure:2688: checking for unistd.h +configure:2704: gcc -c -g -O2 conftest.c >&5 +configure:2710: $? = 0 +configure:2714: test -z + || test ! -s conftest.err +configure:2717: $? = 0 +configure:2720: test -s conftest.o +configure:2723: $? = 0 +configure:2734: result: yes +configure:2895: checking for egrep +configure:2905: result: grep -E +configure:2912: checking whether linking with rpath is requested +configure:2922: result: no +configure:2970: checking for lua +configure:2989: found /usr/bin/lua +configure:3001: result: /usr/bin/lua +configure:3083: checking lua.h usability +configure:3095: gcc -c -g -O2 conftest.c >&5 +conftest.c:53:17: fatal error: lua.h: No such file or directory +compilation terminated. +configure:3101: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| +| #define PACKAGE_NAME "lua-sqlite3" +| #define PACKAGE_TARNAME "lua-sqlite3" +| #define PACKAGE_VERSION "0.4" +| #define PACKAGE_STRING "lua-sqlite3 0.4" +| #define PACKAGE_BUGREPORT "mroth@nessie.de" +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| /* end confdefs.h. */ +| #include +| #if HAVE_SYS_TYPES_H +| # include +| #endif +| #if HAVE_SYS_STAT_H +| # include +| #endif +| #if STDC_HEADERS +| # include +| # include +| #else +| # if HAVE_STDLIB_H +| # include +| # endif +| #endif +| #if HAVE_STRING_H +| # if !STDC_HEADERS && HAVE_MEMORY_H +| # include +| # endif +| # include +| #endif +| #if HAVE_STRINGS_H +| # include +| #endif +| #if HAVE_INTTYPES_H +| # include +| #else +| # if HAVE_STDINT_H +| # include +| # endif +| #endif +| #if HAVE_UNISTD_H +| # include +| #endif +| #include +configure:3124: result: no +configure:3128: checking lua.h presence +configure:3138: gcc -E conftest.c +conftest.c:19:17: fatal error: lua.h: No such file or directory +compilation terminated. +configure:3144: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| +| #define PACKAGE_NAME "lua-sqlite3" +| #define PACKAGE_TARNAME "lua-sqlite3" +| #define PACKAGE_VERSION "0.4" +| #define PACKAGE_STRING "lua-sqlite3 0.4" +| #define PACKAGE_BUGREPORT "mroth@nessie.de" +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| /* end confdefs.h. */ +| #include +configure:3164: result: no +configure:3199: checking for lua.h +configure:3206: result: no +configure:3213: error: Cannot find lua.h + +## ---------------- ## +## Cache variables. ## +## ---------------- ## + +ac_cv_c_compiler_gnu=yes +ac_cv_env_CC_set= +ac_cv_env_CC_value= +ac_cv_env_CFLAGS_set= +ac_cv_env_CFLAGS_value= +ac_cv_env_CPPFLAGS_set= +ac_cv_env_CPPFLAGS_value= +ac_cv_env_CPP_set= +ac_cv_env_CPP_value= +ac_cv_env_LDFLAGS_set= +ac_cv_env_LDFLAGS_value= +ac_cv_env_build_alias_set= +ac_cv_env_build_alias_value= +ac_cv_env_host_alias_set= +ac_cv_env_host_alias_value= +ac_cv_env_target_alias_set= +ac_cv_env_target_alias_value= +ac_cv_exeext= +ac_cv_header_inttypes_h=yes +ac_cv_header_lua_h=no +ac_cv_header_memory_h=yes +ac_cv_header_stdc=yes +ac_cv_header_stdint_h=yes +ac_cv_header_stdlib_h=yes +ac_cv_header_string_h=yes +ac_cv_header_strings_h=yes +ac_cv_header_sys_stat_h=yes +ac_cv_header_sys_types_h=yes +ac_cv_header_unistd_h=yes +ac_cv_objext=o +ac_cv_path_LUA=/usr/bin/lua +ac_cv_prog_CPP='gcc -E' +ac_cv_prog_ac_ct_CC=gcc +ac_cv_prog_cc_g=yes +ac_cv_prog_cc_stdc= +ac_cv_prog_egrep='grep -E' + +## ----------------- ## +## Output variables. ## +## ----------------- ## + +CC='gcc' +CFLAGS='-g -O2' +CPP='gcc -E' +CPPFLAGS='' +DEFS='' +ECHO_C='' +ECHO_N='-n' +ECHO_T='' +EGREP='grep -E' +EXEEXT='' +LDFLAGS='' +LIBOBJS='' +LIBS='' +LTLIBOBJS='' +LUA='/usr/bin/lua' +OBJEXT='o' +PACKAGE_BUGREPORT='mroth@nessie.de' +PACKAGE_NAME='lua-sqlite3' +PACKAGE_STRING='lua-sqlite3 0.4' +PACKAGE_TARNAME='lua-sqlite3' +PACKAGE_VERSION='0.4' +PATH_SEPARATOR=':' +SHELL='/bin/bash' +ac_ct_CC='gcc' +bindir='${exec_prefix}/bin' +build_alias='' +datadir='${prefix}/share' +exec_prefix='NONE' +host_alias='' +includedir='${prefix}/include' +infodir='${prefix}/info' +libdir='${exec_prefix}/lib' +libexecdir='${exec_prefix}/libexec' +localstatedir='${prefix}/var' +mandir='${prefix}/man' +oldincludedir='/usr/include' +prefix='NONE' +program_transform_name='s,x,x,' +sbindir='${exec_prefix}/sbin' +sharedstatedir='${prefix}/com' +sysconfdir='${prefix}/etc' +target_alias='' + +## ----------- ## +## confdefs.h. ## +## ----------- ## + +#define HAVE_INTTYPES_H 1 +#define HAVE_MEMORY_H 1 +#define HAVE_STDINT_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_STRINGS_H 1 +#define HAVE_STRING_H 1 +#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_UNISTD_H 1 +#define PACKAGE_BUGREPORT "mroth@nessie.de" +#define PACKAGE_NAME "lua-sqlite3" +#define PACKAGE_STRING "lua-sqlite3 0.4" +#define PACKAGE_TARNAME "lua-sqlite3" +#define PACKAGE_VERSION "0.4" +#define STDC_HEADERS 1 + +configure: exit 1 diff --git a/lua-sqlite3-0.4.1/configure b/lua-sqlite3-0.4.1/configure new file mode 100755 index 0000000..f9f2bce --- /dev/null +++ b/lua-sqlite3-0.4.1/configure @@ -0,0 +1,4490 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.59 for lua-sqlite3 0.4. +# +# Report bugs to . +# +# Copyright (C) 2003 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +# +# Copyright (c) 2006 Michael Roth +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_config_libobj_dir=. +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME='lua-sqlite3' +PACKAGE_TARNAME='lua-sqlite3' +PACKAGE_VERSION='0.4' +PACKAGE_STRING='lua-sqlite3 0.4' +PACKAGE_BUGREPORT='mroth@nessie.de' + +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP LUA LIBOBJS LTLIBOBJS' +ac_subst_files='' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +(cd $srcdir && test -r "./$ac_unique_file") 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures lua-sqlite3 0.4 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +_ACEOF + + cat <<_ACEOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of lua-sqlite3 0.4:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-rpath link with rpath option + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-lua-dir=DIR where you installed lua [EPREFIX] + --with-lua-includedir=DIR + where to find lua headers [LUA_DIR/include] + --with-lua-libdir=DIR where to find the lua library [LUA_DIR/lib] + --with-lua=FILE path to the 'lua' command [LUA_DIR/bin/lua] + --with-sqlite3-dir=DIR where you installed sqlite3 [EPREFIX] + --with-sqlite3-includedir=DIR + where to find sqlite3 headers [SQLITE3_DIR/include] + --with-sqlite3-libdir=DIR + where to find the sqlite3 library [SQLITE3_DIR/lib] + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_srcdir/configure.gnu; then + echo + $SHELL $ac_srcdir/configure.gnu --help=recursive + elif test -f $ac_srcdir/configure; then + echo + $SHELL $ac_srcdir/configure --help=recursive + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd $ac_popdir + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF +lua-sqlite3 configure 0.4 +generated by GNU Autoconf 2.59 + +Copyright (C) 2003 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. + +Copyright (c) 2006 Michael Roth +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by lua-sqlite3 $as_me 0.4, which was +generated by GNU Autoconf 2.59. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_sep= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------- ## +## Output files. ## +## ------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + sed "/^$/d" confdefs.h | sort + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std1 is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std1. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------ ## +## Report this to mroth@nessie.de ## +## ------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep + + + + +echo "$as_me:$LINENO: checking whether linking with rpath is requested" >&5 +echo $ECHO_N "checking whether linking with rpath is requested... $ECHO_C" >&6 +# Check whether --enable-rpath or --disable-rpath was given. +if test "${enable_rpath+set}" = set; then + enableval="$enable_rpath" + rpath=$enableval +else + rpath=no + +fi; +echo "$as_me:$LINENO: result: $rpath" >&5 +echo "${ECHO_T}$rpath" >&6 + + +lua_dir="" +lua_includedir="" +lua_libdir="" +LUA="" + + +# Check whether --with-lua-dir or --without-lua-dir was given. +if test "${with_lua_dir+set}" = set; then + withval="$with_lua_dir" + + lua_dir="${withval}" + lua_includedir="${lua_dir}/include" + lua_libdir="${lua_dir}/lib" + LUA="${lua_dir}/bin/lua" + + +fi; + + +# Check whether --with-lua-includedir or --without-lua-includedir was given. +if test "${with_lua_includedir+set}" = set; then + withval="$with_lua_includedir" + lua_includedir="${withval}" + +fi; + + +# Check whether --with-lua-libdir or --without-lua-libdir was given. +if test "${with_lua_libdir+set}" = set; then + withval="$with_lua_libdir" + lua_libdir="${withval}" + +fi; + + +# Check whether --with-lua or --without-lua was given. +if test "${with_lua+set}" = set; then + withval="$with_lua" + LUA="${withval}" + +fi; + +# Extract the first word of "lua", so it can be a program name with args. +set dummy lua; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_path_LUA+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $LUA in + [\\/]* | ?:[\\/]*) + ac_cv_path_LUA="$LUA" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$bindir:$exec_prefix/bin:$prefix/bin:$PATH" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_LUA="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + ;; +esac +fi +LUA=$ac_cv_path_LUA + +if test -n "$LUA"; then + echo "$as_me:$LINENO: result: $LUA" >&5 +echo "${ECHO_T}$LUA" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + +if test ! -x "${LUA}" ; then + { echo "$as_me:$LINENO: WARNING: No lua interpreter found!" >&5 +echo "$as_me: WARNING: No lua interpreter found!" >&2;} +fi + + +sqlite3_dir="" +sqlite3_includedir="" +sqlite3_libdir="" + + +# Check whether --with-sqlite3-dir or --without-sqlite3-dir was given. +if test "${with_sqlite3_dir+set}" = set; then + withval="$with_sqlite3_dir" + + sqlite3_dir="${withval}" + sqlite3_includedir="${sqlite3_dir}/include" + sqlite3_libdir="${sqlite3_dir}/lib" + + +fi; + + +# Check whether --with-sqlite3-includedir or --without-sqlite3-includedir was given. +if test "${with_sqlite3_includedir+set}" = set; then + withval="$with_sqlite3_includedir" + sqlite3_includedir="${withval}" + +fi; + + +# Check whether --with-sqlite3-libdir or --without-sqlite3-libdir was given. +if test "${with_sqlite3_libdir+set}" = set; then + withval="$with_sqlite3_libdir" + sqlite3_libdir="${withval}" + +fi; + + +if test -n "$lua_includedir" ; then + CFLAGS="-I$lua_includedir $CFLAGS" + CPPFLAGS="-I$lua_includedir $CPPFLAGS" +fi + +if test -n "$lua_libdir" ; then + if test $rpath = yes ; then + LDFLAGS="-Wl,-rpath,${lua_libdir}" + fi + LDFLAGS="-L$lua_libdir $LDFLAGS" +fi + +if test -n "$sqlite3_includedir" -a "$sqlite3_includedir" != "$lua_includedir"; then + CFLAGS="-I$sqlite3_includedir $CFLAGS" + CPPFLAGS="-I$sqlite3_includedir $CPPFLAGS" +fi + +if test -n "$sqlite3_libdir" -a "$sqlite3_libdir" != "$lua_libdir"; then + if test $rpath = yes ; then + LDFLAGS="-Wl,-rpath,${sqlite3_libdir}" + fi + LDFLAGS="-L$sqlite3_libdir $LDFLAGS" +fi + + +if test "${ac_cv_header_lua_h+set}" = set; then + echo "$as_me:$LINENO: checking for lua.h" >&5 +echo $ECHO_N "checking for lua.h... $ECHO_C" >&6 +if test "${ac_cv_header_lua_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_lua_h" >&5 +echo "${ECHO_T}$ac_cv_header_lua_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking lua.h usability" >&5 +echo $ECHO_N "checking lua.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking lua.h presence" >&5 +echo $ECHO_N "checking lua.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: lua.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: lua.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: lua.h: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: lua.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: lua.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: lua.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: lua.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: lua.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: lua.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: lua.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: lua.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: lua.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: lua.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: lua.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: lua.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: lua.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------ ## +## Report this to mroth@nessie.de ## +## ------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for lua.h" >&5 +echo $ECHO_N "checking for lua.h... $ECHO_C" >&6 +if test "${ac_cv_header_lua_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_lua_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_lua_h" >&5 +echo "${ECHO_T}$ac_cv_header_lua_h" >&6 + +fi +if test $ac_cv_header_lua_h = yes; then + : +else + { { echo "$as_me:$LINENO: error: Cannot find lua.h" >&5 +echo "$as_me: error: Cannot find lua.h" >&2;} + { (exit 1); exit 1; }; } +fi + + +if test "${ac_cv_header_lauxlib_h+set}" = set; then + echo "$as_me:$LINENO: checking for lauxlib.h" >&5 +echo $ECHO_N "checking for lauxlib.h... $ECHO_C" >&6 +if test "${ac_cv_header_lauxlib_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_lauxlib_h" >&5 +echo "${ECHO_T}$ac_cv_header_lauxlib_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking lauxlib.h usability" >&5 +echo $ECHO_N "checking lauxlib.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking lauxlib.h presence" >&5 +echo $ECHO_N "checking lauxlib.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: lauxlib.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: lauxlib.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: lauxlib.h: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: lauxlib.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: lauxlib.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: lauxlib.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: lauxlib.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: lauxlib.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: lauxlib.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: lauxlib.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: lauxlib.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: lauxlib.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: lauxlib.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: lauxlib.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: lauxlib.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: lauxlib.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------ ## +## Report this to mroth@nessie.de ## +## ------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for lauxlib.h" >&5 +echo $ECHO_N "checking for lauxlib.h... $ECHO_C" >&6 +if test "${ac_cv_header_lauxlib_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_lauxlib_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_lauxlib_h" >&5 +echo "${ECHO_T}$ac_cv_header_lauxlib_h" >&6 + +fi +if test $ac_cv_header_lauxlib_h = yes; then + : +else + { { echo "$as_me:$LINENO: error: Cannot find lauxlib.h" >&5 +echo "$as_me: error: Cannot find lauxlib.h" >&2;} + { (exit 1); exit 1; }; } +fi + + +if test "${ac_cv_header_sqlite3_h+set}" = set; then + echo "$as_me:$LINENO: checking for sqlite3.h" >&5 +echo $ECHO_N "checking for sqlite3.h... $ECHO_C" >&6 +if test "${ac_cv_header_sqlite3_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_sqlite3_h" >&5 +echo "${ECHO_T}$ac_cv_header_sqlite3_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking sqlite3.h usability" >&5 +echo $ECHO_N "checking sqlite3.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking sqlite3.h presence" >&5 +echo $ECHO_N "checking sqlite3.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: sqlite3.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: sqlite3.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: sqlite3.h: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: sqlite3.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: sqlite3.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: sqlite3.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: sqlite3.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: sqlite3.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: sqlite3.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: sqlite3.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: sqlite3.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: sqlite3.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: sqlite3.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: sqlite3.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: sqlite3.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: sqlite3.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------ ## +## Report this to mroth@nessie.de ## +## ------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for sqlite3.h" >&5 +echo $ECHO_N "checking for sqlite3.h... $ECHO_C" >&6 +if test "${ac_cv_header_sqlite3_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_sqlite3_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_sqlite3_h" >&5 +echo "${ECHO_T}$ac_cv_header_sqlite3_h" >&6 + +fi +if test $ac_cv_header_sqlite3_h = yes; then + : +else + { { echo "$as_me:$LINENO: error: Cannot find sqlite3.h" >&5 +echo "$as_me: error: Cannot find sqlite3.h" >&2;} + { (exit 1); exit 1; }; } +fi + + + + +echo "$as_me:$LINENO: checking if we need -llua" >&5 +echo $ECHO_N "checking if we need -llua... $ECHO_C" >&6 +need_llua=yes +nm -D "$LUA" | $EGREP "T lua_open$" >/dev/null && need_llua=no +echo "$as_me:$LINENO: result: $need_llua" >&5 +echo "${ECHO_T}$need_llua" >&6 +if test $need_llua = yes; then + LIBS="-llua -lm $LIBS" +fi + + +echo "$as_me:$LINENO: checking if we need -llualib" >&5 +echo $ECHO_N "checking if we need -llualib... $ECHO_C" >&6 +if test $need_llua = yes; then + cat >conftest.$ac_ext <<_ACEOF + + #include "lauxlib.h" + int main() + { + luaL_Buffer buf; + luaL_buffinit(0, &buf); + return 0; + } + +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + need_llualib=no +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +need_llualib=yes +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +else + need_llualib=no +fi +echo "$as_me:$LINENO: result: $need_llualib" >&5 +echo "${ECHO_T}$need_llualib" >&6 +if test $need_llualib = yes; then + LIBS="-llualib $LIBS" +fi + +LIBS="-lsqlite3 $LIBS" + + ac_config_files="$ac_config_files Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then we branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +cat >confdef2opt.sed <<\_ACEOF +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g +t quote +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g +t quote +d +: quote +s,[ `~#$^&*(){}\\|;'"<>?],\\&,g +s,\[,\\&,g +s,\],\\&,g +s,\$,$$,g +p +_ACEOF +# We use echo to avoid assuming a particular line-breaking character. +# The extra dot is to prevent the shell from consuming trailing +# line-breaks from the sub-command output. A line-break within +# single-quotes doesn't work because, if this script is created in a +# platform that uses two characters for line-breaks (e.g., DOS), tr +# would break. +ac_LF_and_DOT=`echo; echo .` +DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'` +rm -f confdef2opt.sed + + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by lua-sqlite3 $as_me 0.4, which was +generated by GNU Autoconf 2.59. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Report bugs to ." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +lua-sqlite3 config.status 0.4 +configured by $0, generated by GNU Autoconf 2.59, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2003 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF + + + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@CPP@,$CPP,;t t +s,@EGREP@,$EGREP,;t t +s,@LUA@,$LUA,;t t +s,@LIBOBJS@,$LIBOBJS,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/lua-sqlite3-0.4.1/configure.ac b/lua-sqlite3-0.4.1/configure.ac new file mode 100644 index 0000000..9c31044 --- /dev/null +++ b/lua-sqlite3-0.4.1/configure.ac @@ -0,0 +1,141 @@ +AC_INIT(lua-sqlite3, 0.4, mroth@nessie.de) +AC_COPYRIGHT([Copyright (c) 2006 Michael Roth ]) + + +AC_PROG_CC() +AC_CHECK_HEADERS() +AC_PROG_EGREP() + + +AC_MSG_CHECKING([whether linking with rpath is requested]) +AC_ARG_ENABLE(rpath, + AC_HELP_STRING([--enable-rpath], [link with rpath option]), + rpath=$enableval, + rpath=no +) +AC_MSG_RESULT($rpath) + + +lua_dir="" +lua_includedir="" +lua_libdir="" +LUA="" + +AC_ARG_WITH(lua-dir, + [AC_HELP_STRING(--with-lua-dir=DIR, [where you installed lua [EPREFIX]]) ], + [ + lua_dir="${withval}" + lua_includedir="${lua_dir}/include" + lua_libdir="${lua_dir}/lib" + LUA="${lua_dir}/bin/lua" + ] +) + +AC_ARG_WITH(lua-includedir, + [AC_HELP_STRING(--with-lua-includedir=DIR, [where to find lua headers [LUA_DIR/include]])], + lua_includedir="${withval}" +) + +AC_ARG_WITH(lua-libdir, + [AC_HELP_STRING(--with-lua-libdir=DIR, [where to find the lua library [LUA_DIR/lib]])], + lua_libdir="${withval}" +) + +AC_ARG_WITH(lua, + [AC_HELP_STRING(--with-lua=FILE, [path to the 'lua' command [LUA_DIR/bin/lua]])], + LUA="${withval}" +) + +AC_PATH_PROG(LUA, lua, [], [$bindir:$exec_prefix/bin:$prefix/bin:$PATH]) + +if test ! -x "${LUA}" ; then + AC_MSG_WARN([No lua interpreter found!]) +fi + + +sqlite3_dir="" +sqlite3_includedir="" +sqlite3_libdir="" + +AC_ARG_WITH(sqlite3-dir, + [AC_HELP_STRING(--with-sqlite3-dir=DIR, [where you installed sqlite3 [EPREFIX]])], + [ + sqlite3_dir="${withval}" + sqlite3_includedir="${sqlite3_dir}/include" + sqlite3_libdir="${sqlite3_dir}/lib" + ] +) + +AC_ARG_WITH(sqlite3-includedir, + [AC_HELP_STRING(--with-sqlite3-includedir=DIR, [where to find sqlite3 headers [SQLITE3_DIR/include]])], + sqlite3_includedir="${withval}" +) + +AC_ARG_WITH(sqlite3-libdir, + [AC_HELP_STRING(--with-sqlite3-libdir=DIR, [where to find the sqlite3 library [SQLITE3_DIR/lib]])], + sqlite3_libdir="${withval}" +) + + +if test -n "$lua_includedir" ; then + CFLAGS="-I$lua_includedir $CFLAGS" + CPPFLAGS="-I$lua_includedir $CPPFLAGS" +fi + +if test -n "$lua_libdir" ; then + if test $rpath = yes ; then + LDFLAGS="-Wl,-rpath,${lua_libdir}" + fi + LDFLAGS="-L$lua_libdir $LDFLAGS" +fi + +if test -n "$sqlite3_includedir" -a "$sqlite3_includedir" != "$lua_includedir"; then + CFLAGS="-I$sqlite3_includedir $CFLAGS" + CPPFLAGS="-I$sqlite3_includedir $CPPFLAGS" +fi + +if test -n "$sqlite3_libdir" -a "$sqlite3_libdir" != "$lua_libdir"; then + if test $rpath = yes ; then + LDFLAGS="-Wl,-rpath,${sqlite3_libdir}" + fi + LDFLAGS="-L$sqlite3_libdir $LDFLAGS" +fi + + +AC_CHECK_HEADER(lua.h, [], [AC_MSG_ERROR(Cannot find lua.h)]) +AC_CHECK_HEADER(lauxlib.h, [], [AC_MSG_ERROR(Cannot find lauxlib.h)]) +AC_CHECK_HEADER(sqlite3.h, [], [AC_MSG_ERROR(Cannot find sqlite3.h)]) + + +AC_MSG_CHECKING(if we need -llua) +need_llua=yes +nm -D "$LUA" | $EGREP "T lua_open$" >/dev/null && need_llua=no +AC_MSG_RESULT($need_llua) +if test $need_llua = yes; then + LIBS="-llua -lm $LIBS" +fi + + +AC_MSG_CHECKING(if we need -llualib) +if test $need_llua = yes; then + AC_LINK_IFELSE([ + #include "lauxlib.h" + int main() + { + luaL_Buffer buf; + luaL_buffinit(0, &buf); + return 0; + } + ], [need_llualib=no], [need_llualib=yes]) +else + need_llualib=no +fi +AC_MSG_RESULT($need_llualib) +if test $need_llualib = yes; then + LIBS="-llualib $LIBS" +fi + +LIBS="-lsqlite3 $LIBS" + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/lua-sqlite3-0.4.1/documentation.html b/lua-sqlite3-0.4.1/documentation.html new file mode 100644 index 0000000..e0c841f --- /dev/null +++ b/lua-sqlite3-0.4.1/documentation.html @@ -0,0 +1,796 @@ +Lua-Sqlite3 Documentation + +

Lua-Sqlite3 Documentation

+
+

Table of Contents

+
+
+

Overview

+

+Lua-Sqlite3 is a binding of sqlite (http://www.sqlite.org) Version 3 to Lua (http://www.lua.org/). +

+

+Lua-Sqlite3 is unique in contrast to other database bindings that it consists of two layers. +

+

+The first layer, written in C, is called the 'backend'. The backend translates the C-api of the sqlite library version 3 to lua. The backend mainly converts datatypes from C to lua and vice versa and expose most C functions from the sqlite library to lua. +

+

+The second layers are called 'frontends' and are written in lua. A frontend provides a specific view and interface to a database. For example it's the job of a frontend to translate error codes from the sqlite library to error messages in lua. It's also the job of a fronted to arrange for garbage collection of database handles and to make sure, that the functions exposed by the backend are called in the right order. +

+

+Currently, Lua-Sqlite3 implements two frontends: +

+
    +
  1. +An specialiced frontend, simple named 'Sqlite3', which explodes all capabilities of the sqlite library in a comfortable way. +
  2. +
  3. +A frontend, named 'LuaSQL-Sqlite3' which provides a LuaSQL compatible interface as used in the Kepler Project. +
  4. +
+

+The first frontend named 'Sqlite3' provides following advantages: +

+
    +
  • +Works in host programs that use multiple Lua states. +
  • +
  • +No problems in conjunction with Lua coroutines, instead powerfull usage of coroutines possible. +
  • +
  • +Reading result sets using for-loop iterators. +
  • +
  • +Automatic and smart converting of data types. +
  • +
  • +Blocks of multiple SQL statements could be executed at once. +
  • +
  • +User functions, aggregates and collators in a natural way. +
  • +
  • +Authorize, trace, commit, progress and busy handlers. +
  • +
+

+The second frontend named 'LuaSQL-Sqlite3' is fully compatible with the database standard defined by the Kepler Project. This frontend provides currently no extensions. +

+
+

Summary

+

+The complete package is named 'Lua-Sqlite3'. It consists of a backend, named 'libluasqlite3' and currently two frontends, named 'Sqlite3' and 'LuaSQL-Sqlite3'. +

+

+The backend is a thin wrapper to expose the C-api of sqlite library version 3 to lua. The backend is written in C. +

+

+The frontends are build on top of the backend and are written in lua. The frontends provide a specific interface to a database. +

+
+
+

Installation

+

+Lua-Sqlite3 comes with a configure script to customize the paths where to install and where to find headers and libraries. +

+

+The configure options --with-lua-dir and --with-sqlite3-dir tell where you installed lua and sqlite3 to search for headers and libraries. +

+

+If you are using shared libraries and didn't installed sqlite3 or lua to a standard directory searched by the dynamic linker of your operating system, you could run configure with --enable-rpath to make sure, that Lua-Sqlite3 will find the shared libraries without setting LD_LIBRARY_PATH. +

+

+After you run configure, run make to build the C-library. After successfull build of the C-library you could also run the provided testsuite to make sure all work as expected and finally install the package. +

+
+# ./configure --help
+# ./configure ...
+# make all
+# make check
+# make install
+
+

+If you plan to use Lua-Sqlite3 on Windows or if you would like to link Lua-Sqlite3 statically to your host program, you should fiddle with the backend loader, a lua function named load_libluasqlite3() defined in the file libluasqlite3-loader.lua. Actually this file is created from a template, called libluasqlite3-loader.lua.in. The changes needed to the loader should be obvious. +

+

+Warning: Maybe the loader process and behaviour will change in future releases again. +

+

+Warning 2: The loader process will definitively change when Lua-Sqlite3 drops support for Lua-5.0 while switching to Lua-5.1 package style. +

+
+
+

Sqlite3 Frontend

+

+The Lua-Sqlite3 frontend provides an object oriented view to a sqlite3 database. There are only two types of objects: A database object and a statement object. The objects itself are really tables, but that doesn't matters. +

+

+A Database object is created when opening a database was successfull. A statement object is created when you compile a SQL statement using an open database object. +

+

+These objects provide different methods that you call to perform the desired function. There are methods to close objects and methods to execute SQL statements. +

+

+A method is always called with the colon syntax. An error is raised, if you use a dot ('.') instead a colon (':').for example: +

+
+-- Ok
+db:close()
+
+-- Error! Don't do this!
+db.close()
+
+-- This works too, but doesn't look nice and is error prone
+db.close(db)
+
+

+However, there is an exception. The 'sqlite3' namespace isn't an object, it's just a namespace, a table with functions. You must use a dot ('.'), using a colon (':') results in undefined behaviour or raises an error. +

+
+

Error handling

+

+If a method on any Lua-Sqlite3 object was successfull, something is returned that evaluates to true, if used in an expression. Mostly these are newly created objects or returned rows. +

+

+There are two possible error sources: +

+
    +
  1. +Errors in the application, for example SQL syntax errors, closing a database twice or trying to execute a statement on a closed database. +
  2. +
  3. +Errors reported from sqlite3 itself, for example a locked database, or an interrupted query and so on. +
  4. +
+

+In the first case, an error in Lua-Sqlite3 usage, the error is reported with the Lua function error(), which results in terminating the last protected function call. +

+

+In the second case, when an error during executing a SQL statement occurs, two values are returned: A nil value and an string containing the error message. +

+

+This behaviour will result in easy catching of all errors using assert() and pcall(): +

+
+function foobar()
+  assert( some_sqlite3_function() )
+  assert( another_sqlite3_call() )
+  assert( a_third_call_to_sqlite3() )
+end
+
+ok, errmsg = pcall( foobar )
+
+if not ok then
+  print("An database error occurred:", errmsg)
+end
+
+
+

Open and Close

+

+You can open a database that resides in a file on a disc, or you could open a database in memory. As stated above, make sure you use a single point ('.') to call the functions in the 'sqlite3' namespace. Don't use a colon (':') because 'sqlite3' isn't an object: +

+
+-- Open a file database
+db = sqlite3.open("filename")
+
+-- Open a temporary database in memory
+db = sqlite3.open_memory()
+
+

+To close a database you invoke the method db:close(). Because this call is a method on the database object, you must use a colon (':') to separate the method name from the object name: +

+
+db:close()
+
+

+If you close a database, all uncommitted transactions are rolled back, all resources are released automatically. You don't need to close other objects related to this database, but if you would like, you could do so. +

+

+If closing the database was successfull db:close() returns the database object itself. +

+

+If there was an error, for example closing the same database twice, an error is raised. When there was an error in sqlite3 itself, a nil and the error message is returned. +

+
+

Executing simple SQL Statements

+

+To execute SQL statements which don't return rows, user db:exec() with the SQL statement as an argument: +

+
+db:exec( "CREATE TABLE test (id, data)" )
+db:exec[[ INSERT INTO test VALUES (1, "Hello World") ]]
+
+

+You can also execute multiple SQL statements using a single db:exec() call. The only prerequisite is that none of the statements return rows. You can use statements like CREATE, INSERT, UPDATE, DELETE and so on, but you can't issue a SELECT statement inside a multiple db:exec(). Doing so will raise an error. +

+

+Multiple SQL statements must be separated using semicolons: +

+
+db:exec[[
+  BEGIN TRANSACTION;
+    CREATE TABLE test (id, data);
+      INSERT INTO test VALUES (1, "Hello World");
+      INSERT INTO test VALUES (2, "Hello Lua");
+      INSERT INTO test VALUES (3, "Hello Sqlite3");
+  END TRANSACTION
+]]
+
+
+

Fetching Rows using SELECT Statements

+

+To execute a SELECT statement, you can't use db:exec(). Doing so raises an error instead. +

+

+Rows returned from SELECT statements are fetched using an interator. This works like ipairs() or pairs() in for-loops on tables. +

+

+You have to choose among three different ways, how the fetched rows should be returned to your loop: +

+
    +
  1. +For each row an array with column data is returned. The columns are indexed with integers. +
  2. +
  3. +For each row a table with the column data is returned, but the columns are indexed with the column names. +
  4. +
  5. +Each column data is returned directly. +
  6. +
+

+An example will make this clear: +

+
+-- Returns a row as an integer indexed array
+for row in db:irows("SELECT * FROM test") do
+  print(row[1], row[2])
+end
+
+-- Returns a row as an table, indexed by column names
+for row in db:rows("SELECT * FROM test") do
+  print(row.id, row.data)
+end
+
+-- Returns each column directly
+for id, data in db:cols("SELECT * FROM test") do
+  print(id, data)
+end
+
+

+Using db:cols() there exists a subtle caveat: By definition, a for loop in Lua terminates when the first value in the returned values is nil. So you can't use the db:cols() iterator, if your SELECT statement returns rows which first column may contain NULLs (which are converted to NIL). If you do so, immediately before the row that first column contains a NULL, the loop will terminate early. +

+

+To prevent this behaviour, you could either make sure that the first column in your SELECT statement will never be NULL, for example the first column could always be a row id, or alternatively you could insert a constant and a dummy variable. Example: +

+
+for _, id, data in db:cols("SELECT 1, * FROM test") do
+  print(id, data)
+end
+
+

+This loop will always return all rows, because the first column is always '1' (the '1' is stored in the dummy variable '_'). +

+
+

Fetching a Single Row

+

+Often you only need the first row that a SELECT statement returns. For example counting the number of rows in a table and so on. Using db:rows() and related for such a task is a mess, instead you should use db:first_row() and related for this task: +

+
+row = db:first_irow("SELECT count(*) FROM test")
+print(row[1])
+
+row = db:first_row("SELECT count(*) AS count FROM test")
+print(row.count)
+
+count = db:first_cols("SELECT count(*) FROM test")
+print(count)
+
+

+There doesn't exist a caveat in db:first_cols() like in db:cols(), instead always exactly the columns of the first row from the SELECT statement are returned. +

+
+

Simple Prepared Statements

+

+If you have to repeatedly execute the same SQL statement, it will be more efficient if you compile those statements and reuse the compiled form multiple times. +

+

+When a statement becomes compiled, the statement is parsed and translated to a virtual machine which is stored in a binary representation form in the sqlite3 library itself. This results in a much faster execution of the statement because every time you reuse a compiled statement, the parsing and building of the virtual machine is omitted. +

+

+Compiling a statement is done with db:prepare(). It will return a compiled statement object: +

+
+stmt = db:prepare("SELECT * FROM test")
+
+

+To use a compiled statement, it defines the same methods to execute and query a statement like the db object itself. The examples above could be rewritten to: +

+
+stmt = db:prepare("SELECT * FROM test")
+
+for row in stmt:irows() do
+  print(row[1], row[2])
+end
+
+for row in stmt:rows() do
+  print(row.id, row.data)
+end
+
+for id, data in stmt:cols() do
+  print(id, data)
+end
+
+

+And: +

+
+stmt = db:prepare("SELECT count(*) AS count FROM test")
+
+row = stmt:first_irow()
+print(row[1])
+
+row = stmt:first_row()
+print(row.count)
+
+count = stmt:first_cols()
+print(count)
+
+

+You could even compile multiple SQL statements: +

+
+stmt = db:prepare[[
+    INSERT INTO test VALUES (1, "Hello World");
+    INSERT INTO test VALUES (2, "Hello Lua");
+    INSERT INTO test VALUES (3, "Hello Sqlite3")
+]]
+
+stmt:exec()
+
+
+

Prepared Statements with Parameters (Binding)

+

+You can compile SQL statements with placeholder or parameters. So you can reuse the statements later and bind values to the placeholders. With this you can easily reuse parameterized and complicated SQL statements. +

+

+There are two possibilities to use placeholders or parameters. Mixing the two possibilities in a single compiled statement is not allowed. +

+
    +
  1. +Numbered, anonymous parameters using '?'. +
  2. +
  3. +Named parameters using ':name' or '$name'. +
  4. +
+

Anonymous Parameters

+

+To use a anonymous parameter simply insert a questionmark ('?') in your SQL statement where you would like later bind values to. Then, after you compiled your SQL statement using db:prepare() everytime you would like to bind values to your placeholders, call stmt:bind() to bind the values. The arguments to stmt:bind() are binded to the placeholder in the order the question marks appear in the SQL statement. If the number of arguments to stmt:bind() doesn't match the number of placeholders (questionmarks) in your SQL statement, an error will be raised. +

+

+You could use parameters and bindings with every valid SQL statement. You can even use placeholders with multiple statements: +

+
+insert_stmt = db:prepare[[
+  INSERT INTO test VALUES (?, ?);
+  INSERT INTO test VALUES (?, ?)
+]]
+
+function insert(id1, data1, id2, data2)
+  insert_stmt:bind(id1, data1, id2, data2)
+  insert_stmt:exec()
+end
+
+insert( 1, "Hello World",   2, "Hello Lua" )
+insert( 3, "Hello Sqlite3", 4, "Hello User" )
+
+get_stmt = db:prepare("SELECT data FROM test WHERE test.id = ?")
+
+function get_data(id)
+  get_stmt:bind(id)
+  return get_stmt:first_cols()
+end
+
+print( get_data(1) )
+print( get_data(2) )
+print( get_data(3) )
+print( get_data(4) )
+
+

Named Parameters

+

+If you have to bind a lot of values or if you have to use the same value twice or more times in a SQL statement, using the questionmark as a placeholder is error prone because you have to count the questionmarks and make sure you call stmt:bind() with all the values in the right order. +

+

+Alternatively, you can use named placeholder. A named placeholder is a parameter, which begins with a colon (':') or a dollar sign ('$') followed by alphanumerical characters that build a valid identifier. +

+

+To define the order of your named placeholder to the stmt:bind() function, you can optionally submit an array with the names of your parameters to db:prepare() as the first argument. +

+

+The leading colon or dollar sign is optional in the parameter name array. (But of course, the colon or dollar sign in the SQL statement is mandatory.) +

+

+The ordering of the parameter names in the array determines the order of the arguments to the later stmt:bind() call. +

+
+db:exec("CREATE TABLE person_name (id, name)")
+db:exec("CREATE TABLE person_email (id, email)")
+db:exec("CREATE TABLE person_address (id, address)")
+
+-- '$' and ':' are optional
+parameter_names = { ":id", "$name", "address", "email" }
+
+stmt = db:prepare(parameter_names, [[
+  BEGIN TRANSACTION;
+    INSERT INTO person_name VALUES (:id, :name);
+    INSERT INTO person_email VALUES (:id, :email);
+    INSERT INTO person_address VALUES (:id, :address);
+  COMMIT
+]])
+
+function insert(id, name, address, email)
+  stmt:bind(id, name, address, email)
+  stmt:exec()
+end
+
+insert( 1, "Michael", "Germany", "mroth@nessie.de" )
+insert( 2, "John",    "USA",     "john@usa.org" )
+insert( 3, "Hans",    "France",  "hans@france.com" )
+
+

Automatic Parameter Name Mapping

+

+If you don't submit an array containing parameter names to stmt:prepare() the parameter names array becomes automatically build. The parameter names in the automatically build array are ordered according to their first occurrence in the SQL statement. +

+
+...
+
+stmt = db:prepare[[
+  BEGIN TRANSACTION;
+    INSERT INTO person_name VALUES (:id, :name);
+    INSERT INTO person_email VALUES (:id, :email);
+    INSERT INTO person_address VALUES (:id, :address);
+  COMMIT
+]]
+
+function insert(id, name, address, email)
+  -- Please note the different ordering
+  stmt:bind(id, name, email, address)
+  stmt:exec()
+end
+
+...
+
+

Parameter Passing with a Name/Value Table

+

+If you are using named parameters in your statements, you can pass the arguments to stmt:bind() with a name/value table: +

+
+...
+
+stmt = db:prepare[[
+  BEGIN TRANSACTION;
+    INSERT INTO person_name VALUES (:id, :name);
+    INSERT INTO person_email VALUES (:id, :email);
+    INSERT INTO person_address VALUES (:id, :address);
+  COMMIT
+]]
+
+function insert(id, name, address, email)
+  args = { }
+  args.id = id
+  args.name = name
+  args.address = address
+  args.email = args.email
+  stmt:bind(args)
+  stmt:exec()
+end
+
+-- A shorter version equal to the above
+function insert2(id, name, address, email)
+  stmt:bind{ id=id, name=name, address=address, email=email}
+  stmt:exec()
+end
+
+...
+
+

Querying Parameter Names

+

+To query the available parameters in a compiled statement you can use stmt:parameter_names() which returns an array. The parameter names in the returned array have their leading colon or dollar sign stripped: +

+
+...
+
+stmt = db:prepare[[
+  BEGIN TRANSACTION;
+    INSERT INTO person_name VALUES (:id, :name);
+    INSERT INTO person_email VALUES (:id, :email);
+    INSERT INTO person_address VALUES (:id, :address);
+  COMMIT
+]]
+
+names = stmt:parameter_names()
+
+print( table.getn(names) )      -- "4"
+print( names[1] )               -- "id"
+print( names[2] )               -- "name"
+print( names[3] )               -- "email"
+print( names[4] )               -- "address"
+
+...
+
+
+

Defining User Functions

+

+You can define user functions in Sqlite3. User defined functions are called from the SQL language interpreted by Sqlite3, back to Lua. You can define functions which calculate complicated things or you can use these user defined functions to call back to Lua from SQL triggers. +

+

+You need to submit the name of the user function, the number of arguments the user function receives and the function itself: +

+
+function sql_add_ten(a)
+  return a + 10
+end
+
+db:set_function("add_ten", 1, sql_add_ten)
+
+for id, add_ten, data in db::rows("SELECT id, add_ten(id), data FROM test") do
+  print(id, add_ten, data)
+end
+
+

+You can define functions with variable number of arguments. To do this you have to submit -1 as the number of arguments to db:set_function(). The documentation of sqlite3 states, that any negative number will signal a variable argument function, but at least for sqlite release 3.0.5 this is wrong. +

+
+function my_max(...)
+  local result = 0
+  for _, value in ipairs(arg) do
+    result = math.max(result, value)
+  end
+  return result
+end
+
+db:set_function("my_max", -1, my_max)
+
+max1 = db:first_cols("SELECT my_max(17, 7)")
+max2 = db:first_cols("SELECT my_max(1, 2, 3, 4, 5)")
+
+print(max1, max2)       -- 17     5
+
+
+

Defining User Aggregates

+

+A aggregate is a function, which is called multiple times, for each row in the query once, that returns a single value at the end. It is only slightly more complicate than an ordinary function. +

+

+To define a user aggregate, you have to register a function which returns two functions everytime it is called. The first function is used to update an internal state of the user aggregate and the second function is used to fetch the result from the user aggregate. +

+

+The exact steps are: +

+
    +
  • +Step 1: First a function is called, without any arguments, which normally initialize some accumulators of the user aggregate and returns two functions, which are in most cases closures. +
  • +
  • +Step 2: The first function returned in Step 1 is called for every row once. This function is named the 'step' function. The 'step' functions receives the column data as arguments. The 'step' function doesn't return values. It only collects the data and updates some internal state. +
  • +
  • +Step 3: The second function returned in Step 1 is called exactly once, only after all rows were presented to the 'step' function in Step 2 above. This second function is named the 'finalizer' function. The 'finalizer' function receives one argument, the number of how often the 'step' function in Step 2 was called. The 'finalizer' function returns the result of the aggregate. +
  • +
+

+An example will make this more clear: +

+
+db:exec[[
+  CREATE TABLE numbers (num1, num2);
+  INSERT INTO numbers VALUES(1, 2);
+  INSERT INTO numbers VALUES(3, 4);
+  INSERT INTO numbers VALUES(5, 6);
+]]
+
+function my_product_sum_aggregate()
+  local product_sum = 0
+
+  local function step(a, b)
+    local product = a * b
+    product_sum = product_sum + product
+  end
+
+  local function final(num_called)
+    return product_sum / num_called
+  end
+
+  return step, final
+end
+
+db:set_aggregate("product_sum", 2, my_product_sum_aggregate)
+
+print( db:first_cols("SELECT product_sum(num1, num2) FROM numbers") )
+
+

+You can define user aggregates with variable number of arguments. In works analogous defining user functions with variable number of arguments. +

+
+

Collatores and Collation Handler

+

+Needs to be written... +

+
+

Busy Timeout and Handler

+

+In Sqlite3 there are two ways to deal with locked databases. You can set a timeout or set a handler. +

+

Busy Timeout

+

+If you set a timeout, Sqlite3 will try as many milliseconds as specified: +

+
+-- Open the database
+db = sqlite3.open("filename")
+
+-- Set 2 seconds busy timeout
+db:set_busy_timeout(2 * 1000)
+
+-- Use the database
+db:exec(...)
+
+

Busy Handler

+

+You could also set a handler, which gets called in the most cases if the database is locked. A busy handler could do some other work or wait a few milliseconds. The return value of a busy handler determines if Sqlite3 tries to continue with the current transaction or abort the transaction with a "busy" error. +

+

+If the busy handler returns 0, false or nil, no additional attempts are made by Sqlite3 to proceed with a transaction. All other values result in a new attempt to be made by Sqlite3. +

+

+A busy handler gets called with one argument, the number of attempts prior made without success in a transaction. +

+
+-- Open the database
+db = sqlite3.open("filename")
+
+-- Ten attempts are made to proceed, if the database is locked
+function my_busy_handler(attempts_made)
+  if attempts_made < 10 then
+    return true
+  else
+    return false
+  end
+end
+
+-- Set the new busy handler
+db:set_busy_handler(my_busy_handler)
+
+-- Use the database
+db:exec(...)
+
+
+

Progress, Authorizer, Trace and Commit Handler

+

+You guess it, needs to be written... +

+

+But wait, the trace handler is documented: ;-) +

+

Trace Handler

+

+The trace handler in Sqlite3 isn't really a trace handler but it traces effectively compiling SQL statements. So the trace handler is called every time a db:exec() or db:prepare() is executed. The handler gets one argument with the string that was compiled: +

+
+function mytrace(sql_string)
+  print("Sqlite3:", sql_string)
+end
+
+db:set_trace_handler(mytrace)
+
+

+Note: The tracing behaviour will possible change in future. Then we won't use the internal Sqlite3 trace handler but a self written one which gets called every time a SQL statement is executed. +

+
+

Call Chaining

+

+The Sqlite3 Interface makes it possible, to deploy several techniques to write short and efficient code. +

+

+All methods which doesn't fetch data from the database or creates new objects, return self, like methods in smalltalk. +

+

+So you can easily build nice chains of method calls: +

+
+sql  = "INSERT INTO test VALUES (?, ?)"
+id   = 5
+data = [[That's a matter of taste, if your prefer "'" or '"'.]]
+
+db:prepare(sql):bind(id, data):exec()
+
+
+
+

LuaSQL Frontend

+

+There is also a LuaSQL compatible frontend provided. To use the LuaSQL compatible frontend, open it with: +

+
+require "luasql-sqlite3"
+
+

+The LuaSQL Frontend doesn't use any utility functions from the LuaSQL framework of the Keppler Project because the framework from the Keppler Project assumes that every LuaSQL compatible database layer is written in C which is not true for this Sqlite3 wrapper. But this detail doesn't matter. You could use the LuaSQL frontend with or without any other LuaSQL Keppler Project packages. The LuaSQL frontend is fully compatible and integrates nicely. +

+

+For a complete description of the LuaSQL interface, please take a look at http://www.keplerproject.org/luasql/manual.html. +

+

+Currently LuaSQL-Sqlite3 implements no extensions, but this will change in the near future too. +

+
+
+

libluasqlite3 Wrapper

+

+These parts needs to be written: +

+
    +
  1. +Open Wrapper +
  2. +
  3. +Return values and Error Handling +
  4. +
  5. +API Conventions +
  6. +
  7. +Type Converting +
  8. +
+

+Please be patient... +

+
+
+


+Back to Lua-Sqlite3 +
+Last update: 2006-05-10
+Copyright (c) 2004, 2005, 2006 Michael Roth
+ diff --git a/lua-sqlite3-0.4.1/examples/aggregate.lua b/lua-sqlite3-0.4.1/examples/aggregate.lua new file mode 100644 index 0000000..d705806 --- /dev/null +++ b/lua-sqlite3-0.4.1/examples/aggregate.lua @@ -0,0 +1,41 @@ + +require "path" +require "sqlite3" + + +local db = sqlite3.open_memory() + +assert( db:exec[[ + + CREATE TABLE test (col1, col2); + + INSERT INTO test VALUES (1, 2); + INSERT INTO test VALUES (2, 4); + INSERT INTO test VALUES (3, 6); + INSERT INTO test VALUES (4, 8); + INSERT INTO test VALUES (5, 10); + +]] ) + + +assert( db:set_aggregate("my_stats", 2, function() + + local square_error_sum = 0 + + local function step(a, b) + local error = a - b + local square_error = error * error + square_error_sum = square_error_sum + square_error + end + + local function final(num_called) + return square_error_sum / num_called + end + + return step, final + +end)) + + +local my_stats = db:first_cols("SELECT my_stats(col1, col2) FROM test") +print("my_stats:", my_stats) diff --git a/lua-sqlite3-0.4.1/examples/function.lua b/lua-sqlite3-0.4.1/examples/function.lua new file mode 100644 index 0000000..8c8fab0 --- /dev/null +++ b/lua-sqlite3-0.4.1/examples/function.lua @@ -0,0 +1,28 @@ + +require "path" +require "sqlite3" + + +local db = sqlite3.open_memory() + +assert( db:exec[[ + + CREATE TABLE test (col1, col2); + + INSERT INTO test VALUES (1, 2); + INSERT INTO test VALUES (2, 4); + INSERT INTO test VALUES (3, 6); + INSERT INTO test VALUES (4, 8); + INSERT INTO test VALUES (5, 10); + +]] ) + + +assert( db:set_function("my_sum", 2, function(a, b) + return a + b +end)) + + +for col1, col2, sum in db:cols("SELECT *, my_sum(col1, col2) FROM test") do + print(col1, col2, sum) +end diff --git a/lua-sqlite3-0.4.1/examples/order.lua b/lua-sqlite3-0.4.1/examples/order.lua new file mode 100644 index 0000000..e6f610c --- /dev/null +++ b/lua-sqlite3-0.4.1/examples/order.lua @@ -0,0 +1,118 @@ + +require "path" +require "sqlite3" + + +local db = assert( sqlite3:open_memory() ) + + +assert( db:exec[[ + + CREATE TABLE customer ( + id INTEGER PRIMARY KEY, + name VARCHAR(40) + ); + + CREATE TABLE invoice ( + id INTEGER PRIMARY KEY, + customer INTEGER NOT NULL, + title VARCHAR(80) NOT NULL, + article1 VARCHAR(40) NOT NULL, + price1 REAL NOT NULL, + article2 VARCHAR(40), + price2 REAL + ); + + CREATE TABLE invoice_overflow ( + id INTEGER PRIMARY KEY, + invoice INTEGER NOT NULL, + article VARCHAR(40) NOT NULL, + price REAL NOT NULL + ); + + INSERT INTO customer VALUES( + 1, "Michael" ); + + INSERT INTO invoice VALUES( + 1, 1, "Computer parts", "harddisc", 89.90, "floppy", 9.99 ); + + INSERT INTO customer VALUES( + 2, "John" ); + + INSERT INTO invoice VALUES( + 2, 2, "Somme food", "apples", 2.79, "pears", 5.99 ); + + INSERT INTO invoice_overflow VALUES( + NULL, 2, "grapes", 6.34 ); + + INSERT INTO invoice_overflow VALUES( + NULL, 2, "strawberries", 4.12 ); + + INSERT INTO invoice_overflow VALUES( + NULL, 2, "tomatoes", 6.17 ); + + INSERT INTO invoice VALUES( + 3, 2, "A new car", "Cybercar XL-1000", 65000.00, NULL, NULL ); + +]] ) + + +local function customer_name(id) + local stmt = db:prepare("SELECT name FROM customer WHERE id = ?") + return stmt:bind(id):first_cols() +end + + +local function all_invoices() + return db:rows("SELECT id, customer, title FROM invoice") +end + + +local function all_articles(invoice) + + local function iterator() + local stmt, row + + -- Get the articles that are contained in the invoice table itself. + stmt = db:prepare("SELECT article1, price1, article2, price2 FROM invoice WHERE id = ?") + row = stmt:bind(invoice):first_row() + + -- Every Invoice has at least one article. + coroutine.yield(row.article1, row.price1) + + -- Maybe the Invoice has a second article? + if row.article2 then + + -- Yes, there is a second article, so return it. + coroutine.yield(row.article2, row.price2) + + -- When there was an second article, maybe there are even + -- more articles in the overflow table? We will see... + + stmt = db:prepare("SELECT article, price FROM invoice_overflow WHERE invoice = ? ORDER BY id") + + for row in stmt:bind(invoice):rows() do + coroutine.yield(row.article, row.price) + end + end + end + + return coroutine.wrap(iterator) +end + + +for invoice in all_invoices() do + local id = invoice.id + local name = customer_name(invoice.customer) + local title = invoice.title + + print() + print("Invoice #"..id..", "..name..": '"..title.."'") + print("----------------------------------------") + + for article, price in all_articles(id) do + print( string.format("%20s %8.2f", article, price) ) + end + + print() +end diff --git a/lua-sqlite3-0.4.1/examples/path.lua b/lua-sqlite3-0.4.1/examples/path.lua new file mode 100644 index 0000000..4e9cc69 --- /dev/null +++ b/lua-sqlite3-0.4.1/examples/path.lua @@ -0,0 +1,8 @@ + +local path = "?;?.lua;../?;../?.lua" + +if package == nil then + LUA_PATH = path -- Lua 5.0 +else + package.path = path -- Lua 5.1 +end diff --git a/lua-sqlite3-0.4.1/examples/simple.lua b/lua-sqlite3-0.4.1/examples/simple.lua new file mode 100644 index 0000000..82e5572 --- /dev/null +++ b/lua-sqlite3-0.4.1/examples/simple.lua @@ -0,0 +1,18 @@ + +require "path" +require "sqlite3" + + +local db = sqlite3.open_memory() + +db:exec[[ + CREATE TABLE test (id INTEGER PRIMARY KEY, content); + + INSERT INTO test VALUES (NULL, 'Hello World'); + INSERT INTO test VALUES (NULL, 'Hello Lua'); + INSERT INTO test VALUES (NULL, 'Hello Sqlite3') +]] + +for row in db:rows("SELECT * FROM test") do + print(row.id, row.content) +end diff --git a/lua-sqlite3-0.4.1/examples/smart.lua b/lua-sqlite3-0.4.1/examples/smart.lua new file mode 100644 index 0000000..ebccc7d --- /dev/null +++ b/lua-sqlite3-0.4.1/examples/smart.lua @@ -0,0 +1,18 @@ + +require "path" +require "sqlite3" + + +local db = sqlite3.open_memory() + +db:exec[[ CREATE TABLE test (id INTEGER PRIMARY KEY, content) ]] + +local stmt = db:prepare[[ INSERT INTO test VALUES (:key, :value) ]] + +stmt:bind{ key = 1, value = "Hello World" }:exec() +stmt:bind{ key = 2, value = "Hello Lua" }:exec() +stmt:bind{ key = 3, value = "Hello Sqlite3" }:exec() + +for row in db:rows("SELECT * FROM test") do + print(row.id, row.content) +end diff --git a/lua-sqlite3-0.4.1/examples/statement.lua b/lua-sqlite3-0.4.1/examples/statement.lua new file mode 100644 index 0000000..ce0dc43 --- /dev/null +++ b/lua-sqlite3-0.4.1/examples/statement.lua @@ -0,0 +1,40 @@ + +require "path" +require "sqlite3" + + +local db = sqlite3.open_memory() + +db:exec[[ + CREATE TABLE test ( + id INTEGER PRIMARY KEY, + content VARCHAR + ); +]] + +local insert_stmt = assert( db:prepare("INSERT INTO test VALUES (NULL, ?)") ) + +local function insert(data) + insert_stmt:bind(data) + insert_stmt:exec() +end + +local select_stmt = assert( db:prepare("SELECT * FROM test") ) + +local function select() + for row in select_stmt:rows() do + print(row.id, row.content) + end +end + +insert("Hello World") +print("First:") +select() + +insert("Hello Lua") +print("Second:") +select() + +insert("Hello Sqlite3") +print("Third:") +select() diff --git a/lua-sqlite3-0.4.1/examples/tracing.lua b/lua-sqlite3-0.4.1/examples/tracing.lua new file mode 100644 index 0000000..1c14b7d --- /dev/null +++ b/lua-sqlite3-0.4.1/examples/tracing.lua @@ -0,0 +1,21 @@ +require "path" +require "sqlite3" + + +local db = sqlite3.open_memory() + +db:set_trace_handler( function(sql) + print("Sqlite Trace:", sql) +end ) + +db:exec[[ + CREATE TABLE test ( id INTEGER PRIMARY KEY, content VARCHAR ); + + INSERT INTO test VALUES (NULL, 'Hello World'); + INSERT INTO test VALUES (NULL, 'Hello Lua'); + INSERT INTO test VALUES (NULL, 'Hello Sqlite3'); +]] + +for row in db:rows("SELECT * FROM test") do + -- NOP +end diff --git a/lua-sqlite3-0.4.1/libluasqlite3-loader.lua.in b/lua-sqlite3-0.4.1/libluasqlite3-loader.lua.in new file mode 100644 index 0000000..69efae6 --- /dev/null +++ b/lua-sqlite3-0.4.1/libluasqlite3-loader.lua.in @@ -0,0 +1,50 @@ + +--[[-------------------------------------------------------------------------- + + Author: Michael Roth + + Copyright (c) 2004, 2006 Michael Roth + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--]]-------------------------------------------------------------------------- + + +local shared_lib_name = "libluasqlite3.so" +local shared_lib_init = "luaopen_sqlite3" +local shared_lib_path = "SHARED_LIB_PATH" + +-- Lua-5.0 / Lua-5.1 +local loadlib = loadlib or package.loadlib + +local filename = shared_lib_path.."/"..shared_lib_name +local init, error = loadlib(filename, shared_lib_init) + +local api, ERR, TYPE, AUTH + +if init then + api, ERR, TYPE, AUTH = init() +end + +function load_libluasqlite3() + assert(init, error) + return api, ERR, TYPE, AUTH +end + diff --git a/lua-sqlite3-0.4.1/libluasqlite3.c b/lua-sqlite3-0.4.1/libluasqlite3.c new file mode 100644 index 0000000..5d6f34a --- /dev/null +++ b/lua-sqlite3-0.4.1/libluasqlite3.c @@ -0,0 +1,1641 @@ + + +/* + * Author: Michael Roth + * + * Copyright (c) 2004, 2005, 2006 Michael Roth + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + + + +#include +#include +#include +#include + + +/* + * Not exported to Lua: + * + * sqlite3_get_table Really doesn't make sense, doesn't it? + * + * sqlite3_mprintf Won't work because I don't know now how to pass a variable + * numbers of arguments from lua to a C vararg function. + * + * sqlite3_user_data Makes no sense to export, only for internal usage. + * + */ + + + +#define IS_INT(n) ( ( (lua_Number) ((int)(n)) ) == (n) ) + +#define CAST(type, arg) ( (type)(arg) ) + +#define FUNC(name) static int name (lua_State * L) + + + +#define CB_DATA(ptr) CAST(CB_Data *, (ptr)) + +#define KEY(ptr, id) CAST( void*, CAST(char*,(ptr))+(id) ) + +#define KEY_KEY2VALUE_TABLE(p) KEY((p), 1) +#define KEY_FUNCTION_TABLE(p) KEY((p), 2) +#define KEY_COLLATION_TABLE(p) KEY((p), 3) +#define KEY_COLLNEEDED_DATA(p) KEY((p), 4) +#define KEY_AUTHORIZER_DATA(p) KEY((p), 5) +#define KEY_PROGRESS_DATA(p) KEY((p), 6) +#define KEY_TRACE_DATA(p) KEY((p), 7) +#define KEY_BUSY_DATA(p) KEY((p), 8) +#define KEY_COMMIT_DATA(p) KEY((p), 9) + +#define KEY_XFUNC(p) KEY((p), 1) +#define KEY_XSTEP(p) KEY((p), 2) +#define KEY_XFINAL(p) KEY((p), 3) +#define KEY_XCOMPARE(p) KEY((p), 1) +#define KEY_XNEEDED(p) KEY((p), 1) +#define KEY_XAUTH(p) KEY((p), 1) +#define KEY_XPROGRESS(p) KEY((p), 1) +#define KEY_XTRACE(p) KEY((p), 1) +#define KEY_XBUSY(p) KEY((p), 1) +#define KEY_XCOMMIT(p) KEY((p), 1) + + + +typedef struct +{ + sqlite3 * sqlite3; + lua_State * L; + int key2value_pos; /* Used by callback wrappers to find the key2value array on the lua stack */ +} DB; + + +typedef struct +{ + DB * db; + sqlite3_stmt * stmt; +} Stmt; + + +typedef struct +{ + DB * db; +} CB_Data; + + + + + + +static void push_private_table(lua_State * L, void * table_key); +static void delete_private_value(lua_State * L, void * value_key); + +static CB_Data * new_cb_data(lua_State * L, DB * db); +static CB_Data * get_cb_data(lua_State * L, DB * db, void * data_key); +static CB_Data * get_named_cb_data(lua_State * L, DB * db, void * table_key, int name_pos); + +#define get_function_cb_data(L, db, name_pos) get_named_cb_data((L), (db), KEY_FUNCTION_TABLE(db), name_pos) +#define get_collation_cb_data(L, db, name_pos) get_named_cb_data((L), (db), KEY_COLLATION_TABLE(db), name_pos) +#define get_collneeded_cb_data(L, db) get_cb_data((L), (db), KEY_COLLNEEDED_DATA(db)) +#define get_authorizer_cb_data(L, db) get_cb_data((L), (db), KEY_AUTHORIZER_DATA(db)) +#define get_progress_cb_data(L, db) get_cb_data((L), (db), KEY_PROGRESS_DATA(db)) +#define get_trace_cb_data(L, db) get_cb_data((L), (db), KEY_TRACE_DATA(db)) +#define get_busy_cb_data(L, db) get_cb_data((L), (db), KEY_BUSY_DATA(db)) +#define get_commit_cb_data(L, db) get_cb_data((L), (db), KEY_COMMIT_DATA(db)) + +static void register_callback(lua_State * L, DB * db, void * cb_key, int callback_pos); +static void init_callback_usage(lua_State * L, DB * db); +static void push_callback(lua_State * L, DB * db, void * cb_key); + +static int pop_break_condition(lua_State * L); +static void push_nil_or_string(lua_State * L, const char * str); + + + + +static void push_private_table(lua_State * L, void * table_key) +{ + lua_pushlightuserdata(L, table_key); + lua_rawget(L, LUA_REGISTRYINDEX); + if (lua_isnil(L, -1)) + { + lua_pop(L, 1); + lua_newtable(L); + lua_pushlightuserdata(L, table_key); + lua_pushvalue(L, -2); + lua_rawset(L, LUA_REGISTRYINDEX); + } +} + + +static void delete_private_value(lua_State * L, void * value_key) +{ + lua_pushlightuserdata(L, value_key); + lua_rawget(L, LUA_REGISTRYINDEX); + if (!lua_isnil(L, -1)) + { + lua_pushlightuserdata(L, value_key); + lua_pushnil(L); + lua_rawset(L, LUA_REGISTRYINDEX); + } + lua_pop(L, 1); +} + + +static CB_Data * new_cb_data(lua_State * L, DB * db) +{ + CB_Data * cb_data = lua_newuserdata(L, sizeof(CB_Data)); + cb_data->db = db; + return cb_data; +} + + +static CB_Data * get_cb_data(lua_State * L, DB * db, void * data_key) +{ + CB_Data * cb_data; + + lua_pushlightuserdata(L, data_key); + lua_rawget(L, LUA_REGISTRYINDEX); + + if (lua_isnil(L, -1)) + { + lua_pushlightuserdata(L, data_key); + cb_data = new_cb_data(L, db); + lua_rawset(L, LUA_REGISTRYINDEX); + } + else + cb_data = lua_touserdata(L, -1); + + lua_pop(L, 1); + return cb_data; +} + + +static CB_Data * get_named_cb_data(lua_State * L, DB * db, void * table_key, int name_pos) +{ + CB_Data * cb_data; + + push_private_table(L, table_key); + lua_pushvalue(L, name_pos); + lua_rawget(L, -2); + + if (lua_isnil(L, -1)) + { + lua_pushvalue(L, name_pos); + cb_data = new_cb_data(L, db); + lua_rawset(L, LUA_REGISTRYINDEX); + } + else + cb_data = lua_touserdata(L, -1); + + lua_pop(L, 2); + return cb_data; +} + + +static void register_callback(lua_State * L, DB * db, void * cb_key, int callback_pos) +{ + push_private_table(L, KEY_KEY2VALUE_TABLE(db)); + lua_pushlightuserdata(L, cb_key); + lua_pushvalue(L, callback_pos); + lua_rawset(L, -3); + lua_pop(L, 1); +} + + +static void init_callback_usage(lua_State * L, DB * db) +{ + db->L = L; + db->key2value_pos = 0; /* lazy initialized in push_callback() */ +} + + +static void push_callback(lua_State * L, DB * db, void * cb_key) +{ + if (db->key2value_pos == 0) /* lazy initializing of the key2value table */ + { + push_private_table(L, KEY_KEY2VALUE_TABLE(db)); + db->key2value_pos = lua_gettop(L); + } + + lua_pushlightuserdata(L, cb_key); + lua_rawget(L, db->key2value_pos); +} + + +static int pop_break_condition(lua_State * L) +{ + int result; + + if (lua_isnil(L, -1)) + result = 0; + else if (lua_isboolean(L, -1)) + result = lua_toboolean(L, -1); + else if (lua_isnumber(L, -1)) + result = lua_tonumber(L, -1); + else + result = 1; + + lua_pop(L, 1); + return result; +} + + +static void push_nil_or_string(lua_State * L, const char * str) +{ + if (str) + lua_pushstring(L, str); + else + lua_pushnil(L); +} + + + + +/* + * Error Handling + * ============== + * + * We try to work hard to be bullet proof. We even try to function + * correctly in low memory situations. + * Usage errors of the API when detected raise an error also + * memory errors and such. + * Errors signaled from the sqlite library will result in the + * appropriate return codes. + * + */ + + +static void report_error(lua_State * L, const char * msg) +{ + lua_settop(L, 0); /* Clear the stack to make sure, our error message will get a chance */ + lua_pushstring(L, msg); + lua_error(L); +} + + + +#define checkany(L, narg) ( luaL_checkany((L), (narg)) ) +#define checkstr(L, narg) ( luaL_checklstring((L), (narg), 0) ) +#define checknumber(L, narg) ( luaL_checknumber((L), (narg)) ) +#define checkint(L, narg) ( (int) checknumber((L), (narg)) ) +#define checkdouble(L, narg) ( (double) checknumber((L), (narg)) ) + +static void * checkudata(lua_State * L, int narg) +{ + if (!lua_isuserdata(L, narg)) + luaL_typerror(L, narg, "userdata"); + return lua_touserdata(L, narg); +} + +#define checkcontext(L, narg) ( (sqlite3_context *) checkudata((L), (narg)) ) +#define checkvalues(L, narg) ( (sqlite3_value **) checkudata((L), (narg)) ) +#define checkstmt(L, narg) ( (Stmt *) checkudata((L), (narg)) ) +#define checkdb(L, narg) ( (DB *) checkudata((L), (narg)) ) + +static sqlite3_stmt * checkstmt_stmt(lua_State * L, int narg) +{ + return checkstmt(L, narg)->stmt; +} + +static sqlite3 * checkdb_sqlite3(lua_State * L, int narg) +{ + return checkdb(L, narg)->sqlite3; +} + +static int checknilornoneorfunc(lua_State * L, int narg) +{ + if (lua_isnil(L, narg) || lua_isnone(L, narg)) + return 0; + if (lua_isfunction(L, narg)) + return 1; + luaL_typerror(L, narg, "nil, none or function"); + return 0; /* never reached, make compiler happy... */ +} + + + + + + +FUNC( l_sqlite3_bind_null ) +{ + lua_pushnumber(L, sqlite3_bind_null(checkstmt_stmt(L, 1), checkint(L, 2)) ); + return 1; +} + + +FUNC( l_sqlite3_bind_text ) +{ + lua_pushnumber(L, sqlite3_bind_text(checkstmt_stmt(L, 1), checkint(L, 2), checkstr(L, 3), lua_strlen(L, 3), SQLITE_TRANSIENT) ); + return 1; +} + + +FUNC( l_sqlite3_bind_blob ) +{ + lua_pushnumber(L, sqlite3_bind_blob(checkstmt_stmt(L, 1), checkint(L, 2), checkstr(L, 3), lua_strlen(L, 3), SQLITE_TRANSIENT) ); + return 1; +} + + +FUNC( l_sqlite3_bind_int ) +{ + lua_pushnumber(L, sqlite3_bind_int(checkstmt_stmt(L, 1), checkint(L, 2), checkint(L, 3)) ); + return 1; +} + + +FUNC( l_sqlite3_bind_double ) +{ + lua_pushnumber(L, sqlite3_bind_double(checkstmt_stmt(L, 1), checkint(L, 2), checkdouble(L, 3)) ); + return 1; +} + + +FUNC( l_sqlite3_bind_number ) +{ + sqlite3_stmt * stmt = checkstmt_stmt(L, 1); + int index = checkint(L, 2); + lua_Number number = checknumber(L, 3); + + if (IS_INT(number)) + lua_pushnumber(L, sqlite3_bind_int(stmt, index, (int)number) ); + else + lua_pushnumber(L, sqlite3_bind_double(stmt, index, (double)number) ); + + return 1; +} + + +FUNC( l_sqlite3_bind ) +{ + sqlite3_stmt * stmt = checkstmt_stmt(L, 1); + int index = checkint(L, 2); + + switch(lua_type(L, 3)) + { + case LUA_TNONE: + case LUA_TNIL: + lua_pushnumber(L, sqlite3_bind_null(stmt, index) ); + break; + + case LUA_TNUMBER: + { + lua_Number number = lua_tonumber(L, 3); + + if (IS_INT(number)) + lua_pushnumber(L, sqlite3_bind_int(stmt, index, (int)number) ); + else + lua_pushnumber(L, sqlite3_bind_double(stmt, index, (double)number) ); + } + break; + + case LUA_TBOOLEAN: + if (lua_toboolean(L, 3)) + lua_pushnumber(L, sqlite3_bind_int(stmt, index, 1) ); + else + lua_pushnumber(L, sqlite3_bind_int(stmt, index, 0) ); + break; + + case LUA_TSTRING: + lua_pushnumber(L, sqlite3_bind_text(stmt, index, lua_tostring(L, 3), lua_strlen(L, 3), SQLITE_TRANSIENT) ); + break; + + default: + luaL_argerror(L, 3, "nil, boolean, number or string expected"); + } + + return 1; +} + + +FUNC( l_sqlite3_bind_parameter_count ) +{ + lua_pushnumber(L, sqlite3_bind_parameter_count(checkstmt_stmt(L, 1)) ); + return 1; +} + + +FUNC( l_sqlite3_bind_parameter_name ) +{ + const char * name = sqlite3_bind_parameter_name(checkstmt_stmt(L, 1), checkint(L, 2)); + if (name) + lua_pushstring(L, name); + else + lua_pushnil(L); + return 1; +} + + +FUNC( l_sqlite3_bind_parameter_name_x ) +{ + const char * name = sqlite3_bind_parameter_name(checkstmt_stmt(L, 1), checkint(L, 2)); + if (name && *name) + lua_pushstring(L, name + 1); /* Ignore leading '$' or ':' */ + else + lua_pushnil(L); + return 1; +} + + +FUNC( l_sqlite3_busy_timeout ) +{ + DB * db = checkdb(L, 1); + int timeout = checkint(L, 2); + + delete_private_value(L, KEY_BUSY_DATA(db)); + + lua_pushnumber(L, sqlite3_busy_timeout(db->sqlite3, timeout) ); + return 1; +} + + +FUNC( l_sqlite3_changes ) +{ + lua_pushnumber(L, sqlite3_changes(checkdb_sqlite3(L, 1)) ); + return 1; +} + + +FUNC( l_sqlite3_close ) +{ + DB * db = checkdb(L, 1); + + delete_private_value(L, KEY_KEY2VALUE_TABLE(db)); + delete_private_value(L, KEY_FUNCTION_TABLE(db)); + delete_private_value(L, KEY_COLLATION_TABLE(db)); + delete_private_value(L, KEY_COLLNEEDED_DATA(db)); + delete_private_value(L, KEY_AUTHORIZER_DATA(db)); + delete_private_value(L, KEY_PROGRESS_DATA(db)); + delete_private_value(L, KEY_TRACE_DATA(db)); + delete_private_value(L, KEY_BUSY_DATA(db)); + delete_private_value(L, KEY_COMMIT_DATA(db)); + + lua_pushnumber(L, sqlite3_close(db->sqlite3) ); + return 1; +} + + +typedef const char * (*column_text_blob_t)(sqlite3_stmt *, int); + +static int l_sqlite3_column_text_or_blob(lua_State * L, column_text_blob_t column_text_blob) +{ + sqlite3_stmt * stmt = checkstmt_stmt(L, 1); + int column = checkint(L, 2); + + lua_pushlstring(L, column_text_blob(stmt, column), sqlite3_column_bytes(stmt, column)); + return 1; +} + +FUNC( l_sqlite3_column_blob ) +{ + return l_sqlite3_column_text_or_blob(L, (column_text_blob_t)sqlite3_column_blob); +} + +FUNC( l_sqlite3_column_text ) +{ + return l_sqlite3_column_text_or_blob(L, (column_text_blob_t)sqlite3_column_text); /* FIXME: remove cast when API changes!!! */ +} + + +FUNC( l_sqlite3_column_int ) +{ + lua_pushnumber(L, sqlite3_column_int(checkstmt_stmt(L, 1), checkint(L, 2)) ); + return 1; +} + + +FUNC( l_sqlite3_column_double ) +{ + lua_pushnumber(L, sqlite3_column_double(checkstmt_stmt(L, 1), checkint(L, 2)) ); + return 1; +} + + +FUNC( l_sqlite3_column_number ) +{ + sqlite3_stmt * stmt = checkstmt_stmt(L, 1); + int column = checkint(L, 2); + + if ( sqlite3_column_type(stmt, column) == SQLITE_INTEGER ) + lua_pushnumber(L, sqlite3_column_int(stmt, column) ); + else + lua_pushnumber(L,sqlite3_column_double(stmt, column) ); + + return 1; +} + + + + +static void push_column(lua_State * L, sqlite3_stmt * stmt, int column) +{ + switch(sqlite3_column_type(stmt, column)) + { + case SQLITE_NULL: + lua_pushnil(L); + break; + + case SQLITE_INTEGER: + lua_pushnumber(L, sqlite3_column_int(stmt, column)); + break; + + case SQLITE_FLOAT: + lua_pushnumber(L, sqlite3_column_double(stmt, column)); + break; + + case SQLITE_TEXT: + lua_pushlstring(L, sqlite3_column_text(stmt, column), sqlite3_column_bytes(stmt, column)); + break; + + case SQLITE_BLOB: + lua_pushlstring(L, sqlite3_column_blob(stmt, column), sqlite3_column_bytes(stmt, column)); + break; + + default: + lua_pushboolean(L, 0); + } +} + + +FUNC( l_sqlite3_column ) +{ + push_column(L, checkstmt_stmt(L, 1), checkint(L, 2)); + return 1; +} + + +/* + * mode: 0 = direct, 1 = integer, 2 = alphanumeric + */ +static int l_sqlite3_row_mode(lua_State * L, int mode) +{ + /* Old code / Just a reminder / To be removed: + ** checkargs(L, 1, 2, CHECK_PTR, CHECK_NILTABLE, 0); + */ + + sqlite3_stmt * stmt = checkstmt_stmt(L, 1); + int num_columns = sqlite3_data_count(stmt); /* Maybe wrong state, so don't use sqlite3_column_count */ + int index; + + /* XXX Should really be cleaned up... Fixme! */ + + if (mode == 0) + lua_checkstack(L, num_columns); + else + if (!lua_istable(L, -1)) + lua_newtable(L); + + for (index=0; indexsqlite3 = sqlite3; + } + else + lua_pushnil(L); + + return 2; /* error code, database */ +} + + +FUNC( l_sqlite3_prepare ) +{ + /* XXX This piece of code is not so nice. This piece should be redone... */ + + DB * db = checkdb(L, 1); + const char * sql = checkstr(L, 2); + int sql_size = lua_strlen(L, 2); + const char * leftover = 0; + sqlite3_stmt * sqlite3_stmt = 0; + int error, leftover_size; + Stmt * stmt; + + init_callback_usage(L, db); /* Needed by trace handler... FIXME: maybe to be removed... */ + + error = sqlite3_prepare(db->sqlite3, sql, sql_size, &sqlite3_stmt, &leftover); + + leftover_size = leftover ? sql + sql_size - leftover : 0; + + lua_pushnumber(L, error); + + stmt = lua_newuserdata(L, sizeof(Stmt)); + stmt->db = checkdb(L, 1); + stmt->stmt = sqlite3_stmt; + + if (leftover_size > 0) + lua_pushlstring(L, leftover, leftover_size); + else + lua_pushnil(L); + + return 3; /* error code, statement, left over */ +} + + +FUNC( l_sqlite3_reset ) +{ + lua_pushnumber(L, sqlite3_reset(checkstmt_stmt(L, 1)) ); + return 1; +} + + +FUNC( l_sqlite3_step ) +{ + Stmt * stmt = checkstmt(L, 1); + init_callback_usage(L, stmt->db); + lua_pushnumber(L, sqlite3_step(stmt->stmt) ); + return 1; +} + + +FUNC( l_sqlite3_total_changes ) +{ + lua_pushnumber(L, sqlite3_total_changes(checkdb_sqlite3(L, 1)) ); + return 1; +} + + + +static int exec_callback_wrapper(void * cb_data, int num_columns, char ** values, char ** names) +{ + int index; + lua_State * L = (lua_State *) cb_data; + + lua_pushvalue(L, 3); /* Callback function, resulting stack position 4 */ + lua_newtable(L); /* Value array, resulting stack position 5 */ + lua_newtable(L); /* Names array, resulting stack position 6 */ + + for(index=0; indexsqlite3, checkstr(L, 2), cb, cb_data, 0) ); + return 1; +} + + + +static void func_callback_wrapper(int which, sqlite3_context * ctx, int num_args, sqlite3_value ** values) +{ + CB_Data * cb_data = sqlite3_user_data(ctx); + DB * db = cb_data->db; + lua_State * L = db->L; + + switch(which) + { + case 0: push_callback(L, db, KEY_XFUNC(cb_data)); break; + case 1: push_callback(L, db, KEY_XSTEP(cb_data)); break; + case 2: push_callback(L, db, KEY_XFINAL(cb_data)); break; + } + + if (lua_isnil(L, -1)) + { + lua_pop(L, 1); + fprintf(stderr, "libluasqlite3: func_callback_wrapper: Warning: function is null\n"); + return; + } + + lua_pushlightuserdata(L, ctx); + + if (values) + { + lua_pushnumber(L, num_args); + lua_pushlightuserdata(L, values); + } + + if (lua_pcall(L, values ? 3 : 1, 0, 0)) + { + fprintf(stderr, "libluasqlite3: func_callback_wrapper: Warning: user function error: %s\n", lua_tostring(L, -1)); + sqlite3_result_error(ctx, lua_tostring(L, -1), lua_strlen(L, -1)); + lua_pop(L, 1); + } +} + +static void xfunc_callback_wrapper(sqlite3_context * ctx, int num_args, sqlite3_value ** values) +{ + func_callback_wrapper(0, ctx, num_args, values); +} + +static void xstep_callback_wrapper(sqlite3_context * ctx, int num_args, sqlite3_value ** values) +{ + func_callback_wrapper(1, ctx, num_args, values); +} + +static void xfinal_callback_wrapper(sqlite3_context * ctx) +{ + func_callback_wrapper(2, ctx, 0, 0); +} + +FUNC( l_sqlite3_create_function ) +{ + DB * db = checkdb(L, 1); + CB_Data * cb_data = get_function_cb_data(L, db, 2); + + void (*xfunc)(sqlite3_context *, int, sqlite3_value **) = 0; + void (*xstep)(sqlite3_context *, int, sqlite3_value **) = 0; + void (*xfinal)(sqlite3_context *) = 0; + + if ( checknilornoneorfunc(L, 4) ) + xfunc = xfunc_callback_wrapper; + else + xfunc = 0; + + if ( checknilornoneorfunc(L, 5) ) + xstep = xstep_callback_wrapper; + else + xstep = 0; + + if ( checknilornoneorfunc(L, 6) ) + xfinal = xfinal_callback_wrapper; + else + xfinal = 0; + + register_callback(L, db, KEY_XFUNC(cb_data), 4); + register_callback(L, db, KEY_XSTEP(cb_data), 5); + register_callback(L, db, KEY_XFINAL(cb_data), 6); + + lua_pushnumber(L, + sqlite3_create_function ( + db->sqlite3, + checkstr(L, 2), + checkint(L, 3), + SQLITE_UTF8, + cb_data, + xfunc, + xstep, + xfinal )); + + return 1; +} + + +int xcompare_callback_wrapper(void * cb_data, int len_a, const void * str_a, int len_b, const void * str_b) +{ + DB * db = CB_DATA(cb_data)->db; + lua_State * L = db->L; + int result; + + push_callback(L, db, KEY_XCOMPARE(cb_data)); + lua_pushlstring(L, str_a, len_a); + lua_pushlstring(L, str_b, len_b); + + if ( lua_pcall(L, 2, 1, 0) ) + result = 0; /* No way to signal errors to sqlite */ + else + result = (int) lua_tonumber(L, -1); + + lua_pop(L, 1); + return result; +} + +FUNC( l_sqlite3_create_collation ) +{ + DB * db = checkdb(L, 1); + CB_Data * cb_data = get_collation_cb_data(L, db, 2); + + int (*xcompare)(void *, int, const void *, int, const void *); + + if ( checknilornoneorfunc(L, 3) ) + xcompare = xcompare_callback_wrapper; + else + xcompare = 0; + + register_callback(L, db, KEY_XCOMPARE(cb_data), 3); + + lua_pushnumber(L, sqlite3_create_collation( + db->sqlite3, checkstr(L, 2), SQLITE_UTF8, cb_data, xcompare) ); + return 1; +} + + +void xneeded_callback_wrapper(void * cb_data, sqlite3 * sqlite3, int eTextRep, const char * collation_name) +{ + DB * db = CB_DATA(cb_data)->db; + lua_State * L = db->L; + + push_callback(L, db, KEY_XNEEDED(cb_data)); + lua_pushstring(L, collation_name); + + if (lua_pcall(L, 1, 0, 0)) + lua_pop(L, 1); +} + +FUNC( l_sqlite3_collation_needed ) +{ + DB * db = checkdb(L, 1); + CB_Data * cb_data = get_collneeded_cb_data(L, db); + + void (*xneeded)(void *, sqlite3 *, int eTextRep, const char *); + + if ( checknilornoneorfunc(L, 2) ) + xneeded = xneeded_callback_wrapper; + else + xneeded = 0; + + register_callback(L, db, KEY_XNEEDED(cb_data), 2); + + lua_pushnumber(L, sqlite3_collation_needed(db->sqlite3, cb_data, xneeded) ); + return 1; +} + + + + +static void xtrace_callback_wrapper(void * cb_data, const char * str) +{ + DB * db = CB_DATA(cb_data)->db; + lua_State * L = db->L; + + push_callback(L, db, KEY_XTRACE(cb_data)); + lua_pushstring(L, str); + + if ( lua_pcall(L, 1, 0, 0) ) + lua_pop(L, 1); /* pop error message and delete it (errors are ignored) */ +} + +FUNC( l_sqlite3_trace ) +{ + DB * db = checkdb(L, 1); + CB_Data * cb_data = get_trace_cb_data(L, db); + + void (*xtrace)(void *, const char *); + + if ( checknilornoneorfunc(L, 2) ) + xtrace = xtrace_callback_wrapper; + else + xtrace = 0; + + register_callback(L, db, KEY_XTRACE(cb_data), 2); + + sqlite3_trace(db->sqlite3, xtrace, cb_data); + + lua_pushnumber(L, SQLITE_OK); + return 1; +} + + + + +FUNC( l_sqlite3_result_null ) +{ + sqlite3_result_null(checkcontext(L, 1)); + return 0; +} + + +FUNC( l_sqlite3_result_error ) +{ + sqlite3_result_error(checkcontext(L, 1), checkstr(L, 2), lua_strlen(L, 2)); + return 0; +} + + +FUNC( l_sqlite3_result_double ) +{ + sqlite3_result_double(checkcontext(L, 1), checkdouble(L, 2)); + return 0; +} + + +FUNC( l_sqlite3_result_int ) +{ + sqlite3_result_int(checkcontext(L, 1), checkint(L, 2)); + return 0; +} + + +FUNC( l_sqlite3_result_number ) +{ + lua_Number number = checknumber(L, 2); + + if (IS_INT(number)) + sqlite3_result_int(checkcontext(L, 1), (int)number); + else + sqlite3_result_double(checkcontext(L, 1), (double)number); + + return 0; +} + + +FUNC( l_sqlite3_result_blob ) +{ + sqlite3_result_blob(checkcontext(L, 1), checkstr(L, 2), lua_strlen(L, 2), SQLITE_TRANSIENT); + return 0; +} + + +FUNC( l_sqlite3_result_text ) +{ + sqlite3_result_text(checkcontext(L, 1), checkstr(L, 2), lua_strlen(L, 2), SQLITE_TRANSIENT); + return 0; +} + + +FUNC( l_sqlite3_result_value ) +{ + sqlite3_value ** values = checkvalues(L, 2); + int index = checkint(L, 3); + sqlite3_result_value(checkcontext(L, 1), values[index] ); + return 0; +} + +FUNC( l_sqlite3_result ) +{ + sqlite3_context * context = checkcontext(L, 1); + + switch(lua_type(L, 2)) + { + case LUA_TNONE: + case LUA_TNIL: + sqlite3_result_null(context); + break; + + case LUA_TNUMBER: + { + lua_Number number = lua_tonumber(L, 2); + + if (IS_INT(number)) + sqlite3_result_int(context, (int)number); + else + sqlite3_result_double(context, (double)number); + } + break; + + case LUA_TBOOLEAN: + if (lua_toboolean(L, 2)) + sqlite3_result_int(context, 1); + else + sqlite3_result_int(context, 0); + break; + + case LUA_TSTRING: + sqlite3_result_text(context, lua_tostring(L, 2), lua_strlen(L, 2), SQLITE_TRANSIENT); + break; + + default: + report_error(L, "libluasqlite3: Api usage error: Invalid argument to l_sqlite3_result:"); + } + + return 0; +} + + +FUNC( l_sqlite3_aggregate_count ) +{ + lua_pushnumber(L, sqlite3_aggregate_count(checkcontext(L, 1)) ); + return 1; +} + + +FUNC( l_sqlite3_aggregate_context ) +{ + lua_pushlightuserdata(L, sqlite3_aggregate_context(checkcontext(L, 1), 1)); + return 1; +} + + +FUNC( l_sqlite3_value_int ) +{ + sqlite3_value ** values = checkvalues(L, 1); + int index = checkint(L, 2); + lua_pushnumber(L, sqlite3_value_int(values[index]) ); + return 1; +} + + +FUNC( l_sqlite3_value_double ) +{ + sqlite3_value ** values = checkvalues(L, 1); + int index = checkint(L, 2); + lua_pushnumber(L, sqlite3_value_double(values[index]) ); + return 1; +} + + +FUNC( l_sqlite3_value_number ) +{ + sqlite3_value ** values = checkvalues(L, 1); + int index = checkint(L, 2); + sqlite3_value * value = values[index]; + if (sqlite3_value_type(value) == SQLITE_INTEGER) + lua_pushnumber(L, sqlite3_value_int(value) ); + else + lua_pushnumber(L, sqlite3_value_double(value) ); + return 1; +} + + +FUNC( l_sqlite3_value_blob ) +{ + sqlite3_value ** values = checkvalues(L, 1); + int index = checkint(L, 2); + lua_pushlstring(L, sqlite3_value_blob(values[index]), sqlite3_value_bytes(values[index]) ); + return 1; +} + + +FUNC( l_sqlite3_value_text ) +{ + sqlite3_value ** values = checkvalues(L, 1); + int index = checkint(L, 2); + lua_pushlstring(L, sqlite3_value_text(values[index]), sqlite3_value_bytes(values[index]) ); + return 1; +} + + +FUNC( l_sqlite3_value ) +{ + sqlite3_value ** values = checkvalues(L, 1); + int index = checkint(L, 2); + sqlite3_value * value = values[index]; + + switch(sqlite3_value_type(value)) + { + case SQLITE_INTEGER: + lua_pushnumber(L, sqlite3_value_int(value) ); + break; + + case SQLITE_FLOAT: + lua_pushnumber(L, sqlite3_value_double(value) ); + break; + + case SQLITE_TEXT: + lua_pushlstring(L, sqlite3_value_text(value), sqlite3_value_bytes(value) ); + break; + + case SQLITE_BLOB: + lua_pushlstring(L, sqlite3_value_blob(value), sqlite3_value_bytes(value) ); + break; + + case SQLITE_NULL: + lua_pushnil(L); + break; + + default: + report_error(L, "libluasqlite3: Internal error: Unknonw SQLITE data type."); + } + return 1; +} + + +FUNC( l_sqlite3_value_type ) +{ + sqlite3_value ** values = checkvalues(L, 1); + int index = checkint(L, 2); + lua_pushnumber(L, sqlite3_value_type(values[index]) ); + return 1; +} + + +FUNC( l_sqlite3_libversion ) +{ + lua_pushstring(L, sqlite3_libversion() ); + return 1; +} + + +int xcommit_callback_wrapper(void * cb_data) +{ + DB * db = CB_DATA(cb_data)->db; + lua_State * L = db->L; + + push_callback(L, db, KEY_XCOMMIT(cb_data)); + + if ( lua_pcall(L, 0, 1, 0) ) + { + lua_pop(L, 1); + return 1; /* on errors, rollback */ + } + + return pop_break_condition(L); +} + +FUNC( l_sqlite3_commit_hook ) +{ + DB * db = checkdb(L, 1); + CB_Data * cb_data = get_commit_cb_data(L, db); + + int (*xcommit)(void *); + + if ( checknilornoneorfunc(L, 1) ) + xcommit = xcommit_callback_wrapper; + else + xcommit = 0; + + register_callback(L, db, KEY_XCOMMIT(cb_data), 2); + sqlite3_commit_hook(db->sqlite3, xcommit, cb_data); + + lua_pushnumber(L, sqlite3_errcode(db->sqlite3) ); + return 1; +} + + +int xprogress_callback_wrapper(void * cb_data) +{ + DB * db = CB_DATA(cb_data)->db; + lua_State * L = db->L; + + push_callback(L, db, KEY_XPROGRESS(cb_data)); + + if ( lua_pcall(L, 0, 1, 0) ) + { + lua_pop(L, 1); + return 1; /* on errors, rollback */ + } + + return pop_break_condition(L); + return 1; +} + +FUNC( l_sqlite3_progress_handler ) +{ + DB * db = checkdb(L, 1); + CB_Data * cb_data = get_progress_cb_data(L, db); + + int (*xprogress)(void *); + + if ( checknilornoneorfunc(L, 1) ) + xprogress = xprogress_callback_wrapper; + else + xprogress = 0; + + register_callback(L, db, KEY_XPROGRESS(cb_data), 3); + sqlite3_progress_handler(db->sqlite3, checkint(L, 2), xprogress, cb_data); + + lua_pushnumber(L, sqlite3_errcode(db->sqlite3) ); + return 1; +} + + +int xbusy_callback_wrapper(void * cb_data, int num_called) +{ + DB * db = CB_DATA(cb_data)->db; + lua_State * L = db->L; + + push_callback(L, db, KEY_XBUSY(cb_data)); + lua_pushnumber(L, num_called); + + if ( lua_pcall(L, 1, 1, 0) ) + { + lua_pop(L, 1); + return 0; /* On errors, sqlite should return SQLITE_BUSY */ + } + + return pop_break_condition(L); /* WARNING: In reality, the semantic is inverted !!!*/ +} + +FUNC( l_sqlite3_busy_handler ) +{ + DB * db = checkdb(L, 1); + CB_Data * cb_data = get_busy_cb_data(L, db); + + int (*xbusy)(void *, int); + + if ( checknilornoneorfunc(L, 2) ) + xbusy = xbusy_callback_wrapper; + else + xbusy = 0; + + register_callback(L, db, KEY_XBUSY(cb_data), 2); + + lua_pushnumber(L, sqlite3_busy_handler(db->sqlite3, xbusy, cb_data) ); + return 1; +} + + + +int xauth_callback_wrapper(void * cb_data, int auth_request, const char * name1, const char * name2, const char * db_name, const char * trigger_name) +{ + DB * db = CB_DATA(cb_data)->db; + lua_State * L = db->L; + int result; + + push_callback(L, db, KEY_XAUTH(cb_data)); + lua_pushnumber(L, auth_request); + push_nil_or_string(L, name1); + push_nil_or_string(L, name2); + push_nil_or_string(L, db_name); + push_nil_or_string(L, trigger_name); + + if ( lua_pcall(L, 5, 1, 0) ) + { + lua_pop(L, 1); + return SQLITE_DENY; /* On errors, sqlite should deny access */ + } + + if (lua_isnumber(L, -1)) + result = lua_tonumber(L, -1); + else + result = SQLITE_DENY; /* Wrong result values should deny access */ + + lua_pop(L, 1); + return result; +} + +FUNC( l_sqlite3_set_authorizer ) +{ + DB * db = checkdb(L, 1); + CB_Data * cb_data = get_authorizer_cb_data(L, db); + + int (*xauth)(void *, int, const char *, const char *, const char *, const char *); + + if ( checknilornoneorfunc(L, 2) ) + xauth = xauth_callback_wrapper; + else + xauth = 0; + + register_callback(L, db, KEY_XAUTH(cb_data), 2); + + lua_pushnumber(L, sqlite3_set_authorizer(db->sqlite3, xauth, cb_data) ); + return 1; +} + + + + + + +typedef struct { char * name; int (*func)(lua_State *); } f_entry; +typedef struct { char * name; int value; } d_entry; + + + +static void f(lua_State * L, f_entry entries[]) +{ + int index; + lua_newtable(L); + for( index=0; entries[index].name; index++) + { + lua_pushstring(L, entries[index].name); + lua_pushcfunction(L, entries[index].func); + lua_rawset(L, -3); + } +} + + + +static void d(lua_State * L, d_entry entries[]) +{ + int index; + lua_newtable(L); + for( index=0; entries[index].name; index++) + { + lua_pushstring(L, entries[index].name); + lua_pushnumber(L, entries[index].value); + lua_rawset(L, -3); + } +} + + + +f_entry api_entries[] = { + { "bind_null", l_sqlite3_bind_null }, + { "bind_text", l_sqlite3_bind_text }, + { "bind_blob", l_sqlite3_bind_blob }, + { "bind_int", l_sqlite3_bind_int }, + { "bind_double", l_sqlite3_bind_double }, + { "bind_number", l_sqlite3_bind_number }, + { "bind", l_sqlite3_bind }, + { "bind_parameter_name", l_sqlite3_bind_parameter_name }, + { "bind_parameter_name_x", l_sqlite3_bind_parameter_name_x }, + { "bind_parameter_count", l_sqlite3_bind_parameter_count }, + { "busy_timeout", l_sqlite3_busy_timeout }, + { "changes", l_sqlite3_changes }, + { "close", l_sqlite3_close }, + { "column_blob", l_sqlite3_column_blob }, + { "column_text", l_sqlite3_column_text }, + { "column_int", l_sqlite3_column_int }, + { "column_double", l_sqlite3_column_double }, + { "column_number", l_sqlite3_column_number }, + { "column", l_sqlite3_column }, + { "column_type", l_sqlite3_column_type }, + { "column_count", l_sqlite3_column_count }, + { "column_decltype", l_sqlite3_column_decltype }, + { "column_name", l_sqlite3_column_name }, + { "complete", l_sqlite3_complete }, + { "data_count", l_sqlite3_data_count }, + { "errcode", l_sqlite3_errcode }, + { "errmsg", l_sqlite3_errmsg }, + { "finalize", l_sqlite3_finalize }, + { "interrupt", l_sqlite3_interrupt }, + { "last_insert_rowid", l_sqlite3_last_insert_rowid }, + { "open", l_sqlite3_open }, + { "prepare", l_sqlite3_prepare }, + { "reset", l_sqlite3_reset }, + { "step", l_sqlite3_step }, + { "total_changes", l_sqlite3_total_changes }, + { "exec", l_sqlite3_exec }, + { "create_function", l_sqlite3_create_function }, + { "create_collation", l_sqlite3_create_collation }, + { "trace", l_sqlite3_trace }, + { "collation_needed", l_sqlite3_collation_needed }, + { "result_null", l_sqlite3_result_null }, + { "result_error", l_sqlite3_result_error }, + { "result_double", l_sqlite3_result_double }, + { "result_int", l_sqlite3_result_int }, + { "result_number", l_sqlite3_result_number }, + { "result_blob", l_sqlite3_result_blob }, + { "result_text", l_sqlite3_result_text }, + { "result_value", l_sqlite3_result_value }, + { "result", l_sqlite3_result }, + { "aggregate_count", l_sqlite3_aggregate_count }, + { "aggregate_context", l_sqlite3_aggregate_context }, + { "value_int", l_sqlite3_value_int }, + { "value_double", l_sqlite3_value_double }, + { "value_number", l_sqlite3_value_number }, + { "value_blob", l_sqlite3_value_blob }, + { "value_text", l_sqlite3_value_text }, + { "value", l_sqlite3_value }, + { "value_type", l_sqlite3_value_type }, + { "libversion", l_sqlite3_libversion }, + { "commit_hook", l_sqlite3_commit_hook }, + { "progress_handler", l_sqlite3_progress_handler }, + { "busy_handler", l_sqlite3_busy_handler }, + { "set_authorizer", l_sqlite3_set_authorizer }, + { "drow", l_sqlite3_drow }, + { "irow", l_sqlite3_irow }, + { "arow", l_sqlite3_arow }, + { 0, 0 } +}; + + +d_entry error_entries[] = { + { "OK", SQLITE_OK }, + { "ERROR", SQLITE_ERROR }, + { "INTERNAL", SQLITE_INTERNAL }, + { "PERM", SQLITE_PERM }, + { "ABORT", SQLITE_ABORT }, + { "BUSY", SQLITE_BUSY }, + { "LOCKED", SQLITE_LOCKED }, + { "NOMEM", SQLITE_NOMEM }, + { "READONLY", SQLITE_READONLY }, + { "INTERRUPT", SQLITE_INTERRUPT }, + { "IOERR", SQLITE_IOERR }, + { "CORRUPT", SQLITE_CORRUPT }, + { "NOTFOUND", SQLITE_NOTFOUND }, + { "FULL", SQLITE_FULL }, + { "CANTOPEN", SQLITE_CANTOPEN }, + { "PROTOCOL", SQLITE_PROTOCOL }, + { "EMPTY", SQLITE_EMPTY }, + { "SCHEMA", SQLITE_SCHEMA }, + { "TOOBIG", SQLITE_TOOBIG }, + { "CONSTRAINT", SQLITE_CONSTRAINT }, + { "MISMATCH", SQLITE_MISMATCH }, + { "MISUSE", SQLITE_MISUSE }, + { "NOLFS", SQLITE_NOLFS }, + { "AUTH", SQLITE_AUTH }, + { "ROW", SQLITE_ROW }, + { "DONE", SQLITE_DONE }, + { "DENY", SQLITE_DENY }, + { "IGNORE", SQLITE_IGNORE }, + { 0, 0 } +}; + + +d_entry type_entries[] = { + { "INTEGER", SQLITE_INTEGER }, + { "INT", SQLITE_INTEGER }, + { "FLOAT", SQLITE_FLOAT }, + { "DOUBLE", SQLITE_FLOAT }, + { "TEXT", SQLITE_TEXT }, + { "BLOB", SQLITE_BLOB }, + { "NULL", SQLITE_NULL }, + { 0, 0 } +}; + + +d_entry auth_entries[] = { + { "CREATE_INDEX", SQLITE_CREATE_INDEX }, + { "CREATE_TABLE", SQLITE_CREATE_TABLE }, + { "CREATE_TRIGGER", SQLITE_CREATE_TRIGGER }, + { "CREATE_VIEW", SQLITE_CREATE_VIEW }, + { "CREATE_TEMP_INDEX", SQLITE_CREATE_TEMP_INDEX }, + { "CREATE_TEMP_TABLE", SQLITE_CREATE_TEMP_TABLE }, + { "CREATE_TEMP_TRIGGER", SQLITE_CREATE_TEMP_TRIGGER }, + { "CREATE_TEMP_VIEW", SQLITE_CREATE_TEMP_VIEW }, + { "DROP_INDEX", SQLITE_DROP_INDEX }, + { "DROP_TABLE", SQLITE_DROP_TABLE }, + { "DROP_TRIGGER", SQLITE_DROP_TRIGGER }, + { "DROP_VIEW", SQLITE_DROP_VIEW }, + { "DROP_TEMP_INDEX", SQLITE_DROP_TEMP_INDEX }, + { "DROP_TEMP_TABLE", SQLITE_DROP_TEMP_TABLE }, + { "DROP_TEMP_TRIGGER", SQLITE_DROP_TEMP_TRIGGER }, + { "DROP_TEMP_VIEW", SQLITE_DROP_TEMP_VIEW }, + { "INSERT", SQLITE_INSERT }, + { "PRAGMA", SQLITE_PRAGMA }, + { "READ", SQLITE_READ }, + { "SELECT", SQLITE_SELECT }, + { "TRANSACTION", SQLITE_TRANSACTION }, + { "UPDATE", SQLITE_UPDATE }, + { "ATTACH", SQLITE_ATTACH }, + { "DETACH", SQLITE_DETACH }, + { 0, 0 } +}; + + + + +int luaopen_sqlite3(lua_State * L) +{ + f(L, api_entries); + d(L, error_entries); + d(L, type_entries); + d(L, auth_entries); + + return 4; /* api, error codes, type codes, auth requests */ +} + + + diff --git a/lua-sqlite3-0.4.1/luasql-sqlite3.lua b/lua-sqlite3-0.4.1/luasql-sqlite3.lua new file mode 100644 index 0000000..5b0fd94 --- /dev/null +++ b/lua-sqlite3-0.4.1/luasql-sqlite3.lua @@ -0,0 +1,270 @@ + +--[[-------------------------------------------------------------------------- + + Author: Michael Roth + + Copyright (c) 2004 Michael Roth + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--]]-------------------------------------------------------------------------- + + + +if luasql == nil then + luasql = { } +end + +if type(luasql) ~= "table" then + error("luasql needs to be a table, but is a "..type(luasql).." already", 2) +end + + + +local env_class = { } +local conn_class = { } +local cur_class = { } + +local env_class_mt = { __index = env_class } +local conn_class_mt = { __index = conn_class } +local cur_class_mt = { __index = cur_class } + +local api, ERR, TYPE, AUTH + +local function setref(t, v) t.ref_counter = v end +local function ref(t) t.ref_counter = t.ref_counter + 1 end +local function unref(t) t.ref_counter = t.ref_counter - 1 end +local function isref(t) return t.ref_counter > 0 end + + + + +function luasql.sqlite3() + if not api then + api, ERR, TYPE, AUTH = load_libluasqlite3() + end + + local env = setmetatable( {}, env_class_mt ) + setref(env, 0) + + env.closed = false + return env +end + + +function env_class.close(env) + if env.closed or isref(env) then return end + env.closed = true + return true +end + + +function env_class.connect_memory(env) + return env_class.connect(env, ":memory:") +end + + +function env_class.connect(env, filename) + if env.closed then return end + + local conn = setmetatable( {}, conn_class_mt ) + setref(conn, 0) + + local err, db = api.open(filename) + + if err ~= ERR.OK then error("api.open: "..err) end + + conn.env = env + conn.db = db + conn.closed = false + conn.autocommit = true + conn.ta_active = false + + ref(env) + return conn +end + + + +function conn_class.close(conn) + if conn.closed or isref(conn) then return end + + api.close(conn.db) + conn.db = nil + + unref(conn.env) + conn.env = nil + + conn.closed = true + return true +end + + + +function conn_class.commit(conn) + if conn.closed or conn.autocommit or not conn.ta_active then return end + api.exec(conn.db, "COMMIT") + conn.ta_active = false + return true +end + +function conn_class.rollback(conn) + if conn.closed or conn.autocommit or not conn.ta_active then return end + api.exec(conn.db, "ROLLBACK") + conn.ta_active = false + return true +end + + +function conn_class.setautocommit(conn, autocommit) + if not conn.autocommit and autocommit then + api.exec("END") + end + conn.autocommit = autocommit + return true +end + + +function conn_class.execute(conn, sql) + if conn.closed then return end + + if not conn.autocommit and not conn.ta_active then + api.exec(conn.db, "BEGIN") + conn.ta_active = true + end + + local err, stmt = api.prepare(conn.db, sql) + + if err ~= ERR.OK then error("api.prepare: "..err) end + + if api.column_count(stmt) == 0 then + -- normal excute, no cursor + err = api.step(stmt) + if err ~= ERR.DONE then + error("api.step: "..err) + end + api.finalize(stmt) + return api.changes(conn.db) + else + -- select, needs cursor + local cur = setmetatable( {}, cur_class_mt ) + + cur.stmt = stmt + cur.finished = false + cur.closed = false + + ref(conn) + ref(conn.env) + cur.conn = conn + + return cur + end + +end + + + + + + +function cur_class.close(cur) + if cur.closed then return end + + if not cur.finished then + api.finalize(cur.stmt) + cur.stmt = nil + end + + unref(cur.conn.env) + unref(cur.conn) + cur.conn = nil + + cur.closed = true + return true +end + + +function cur_class.fetch(cur, t, mode) + if cur.closed or cur.finished then return end + + -- FIXME: write nice error wrapper... + + local err = api.step(cur.stmt) + + if err == ERR.DONE then + api.finalize(cur.stmt) + cur.stmt = nil + cur.finished = true + return + elseif err ~= ERR.ROW then + error("api.step: "..err) + end + + -- FIXME: really ugly block follows.... + + if t == nil and mode == nil then + -- direct mode + return api.drow(cur.stmt) + else + if type(t) == "string" and mode == nil then + mode = t + t = { } + end + if mode == nil then + mode = "n" + end + if type(t) ~= "table" or type(mode) ~= "string" then + error("fetch usage error") + end + + if mode == nil or mode == "n" then + return api.irow(cur.stmt, t) + elseif mode == "a" then + return api.arow(cur.stmt, t) + else + error("unknown mode: "..mode) + end + end +end + + + +local function get_col_desc(cur, desc, api_func) + if cur.closed then return end + if not cur[desc] then + cur[desc] = { } + for index = 1, api.column_count(cur.stmt) do + table.insert( cur[desc], api_func(cur.stmt, index - 1) ) + end + end + return cur[desc] +end + +function cur_class.getcolnames(cur) + return get_col_desc(cur, "colnames", api.column_name) +end + +function cur_class.getcoltypes(cur) + return get_col_desc(cur, "coltypes", api.column_decltype) +end + + + + diff --git a/lua-sqlite3-0.4.1/lunit.lua b/lua-sqlite3-0.4.1/lunit.lua new file mode 100644 index 0000000..1ebec48 --- /dev/null +++ b/lua-sqlite3-0.4.1/lunit.lua @@ -0,0 +1,693 @@ + +--[[-------------------------------------------------------------------------- + + This file is part of lunit 0.4pre (alpha). + + For Details about lunit look at: http://www.nessie.de/mroth/lunit/ + + Author: Michael Roth + + Copyright (c) 2004 Michael Roth + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--]]-------------------------------------------------------------------------- + + + + +----------------------- +-- Intialize package -- +----------------------- + +local P = { } +lunit = P + +-- Import +local type = type +local print = print +local ipairs = ipairs +local pairs = pairs +local string = string +local table = table +local pcall = pcall +local xpcall = xpcall +local traceback = debug.traceback +local error = error +local setmetatable = setmetatable +local rawset = rawset +local orig_assert = assert +local getfenv = getfenv +local setfenv = setfenv +local tostring = tostring + + +-- Start package scope +setfenv(1, P) + + + + +-------------------------------- +-- Private data and functions -- +-------------------------------- + +local run_testcase +local do_assert, check_msg +local stats = { } +local testcases = { } +local stats_inc, tc_mt + + + + +-------------------------- +-- Type check functions -- +-------------------------- + +function is_nil(x) + return type(x) == "nil" +end + +function is_boolean(x) + return type(x) == "boolean" +end + +function is_number(x) + return type(x) == "number" +end + +function is_string(x) + return type(x) == "string" +end + +function is_table(x) + return type(x) == "table" +end + +function is_function(x) + return type(x) == "function" +end + +function is_thread(x) + return type(x) == "thread" +end + +function is_userdata(x) + return type(x) == "userdata" +end + + + + +---------------------- +-- Assert functions -- +---------------------- + +function assert(assertion, msg) + stats_inc("assertions") + check_msg("assert", msg) + do_assert(not not assertion, "assertion failed (was: "..tostring(assertion)..")", msg) -- (convert assertion to bool) + return assertion +end + + +function assert_fail(msg) + stats_inc("assertions") + check_msg("assert_fail", msg) + do_assert(false, "failure", msg) +end + + +function assert_true(actual, msg) + stats_inc("assertions") + check_msg("assert_true", msg) + do_assert(is_boolean(actual), "true expected but was a "..type(actual), msg) + do_assert(actual == true, "true expected but was false", msg) + return actual +end + + +function assert_false(actual, msg) + stats_inc("assertions") + check_msg("assert_false", msg) + do_assert(is_boolean(actual), "false expected but was a "..type(actual), msg) + do_assert(actual == false, "false expected but was true", msg) + return actual +end + + +function assert_equal(expected, actual, msg) + stats_inc("assertions") + check_msg("assert_equal", msg) + do_assert(expected == actual, "expected '"..tostring(expected).."' but was '"..tostring(actual).."'", msg) + return actual +end + + +function assert_not_equal(unexpected, actual, msg) + stats_inc("assertions") + check_msg("assert_not_equal", msg) + do_assert(unexpected ~= actual, "'"..tostring(expected).."' not expected but was one", msg) + return actual +end + + +function assert_match(pattern, actual, msg) + stats_inc("assertions") + check_msg("assert_match", msg) + do_assert(is_string(pattern), "assert_match expects the pattern as a string") + do_assert(is_string(actual), "expected a string to match pattern '"..pattern.."' but was a '"..type(actual).."'", msg) + do_assert(not not string.find(actual, pattern), "expected '"..actual.."' to match pattern '"..pattern.."' but doesn't", msg) + return actual +end + + +function assert_not_match(pattern, actual, msg) + stats_inc("assertions") + check_msg("assert_not_match", msg) + do_assert(is_string(actual), "expected a string to not match pattern '"..pattern.."' but was a '"..type(actual).."'", msg) + do_assert(string.find(actual, pattern) == nil, "expected '"..actual.."' to not match pattern '"..pattern.."' but it does", msg) + return actual +end + + +function assert_nil(actual, msg) + stats_inc("assertions") + check_msg("assert_nil", msg) + do_assert(is_nil(actual), "nil expected but was a "..type(actual), msg) + return actual +end + + +function assert_not_nil(actual, msg) + stats_inc("assertions") + check_msg("assert_not_nil", msg) + do_assert(not is_nil(actual), "nil not expected but was one", msg) + return actual +end + + +function assert_boolean(actual, msg) + stats_inc("assertions") + check_msg("assert_boolean", msg) + do_assert(is_boolean(actual), "boolean expected but was a "..type(actual), msg) + return actual +end + + +function assert_not_boolean(actual, msg) + stats_inc("assertions") + check_msg("assert_not_boolean", msg) + do_assert(not is_boolean(actual), "boolean not expected but was one", msg) + return actual +end + + +function assert_number(actual, msg) + stats_inc("assertions") + check_msg("assert_number", msg) + do_assert(is_number(actual), "number expected but was a "..type(actual), msg) + return actual +end + + +function assert_not_number(actual, msg) + stats_inc("assertions") + check_msg("assert_not_number", msg) + do_assert(not is_number(actual), "number not expected but was one", msg) + return actual +end + + +function assert_string(actual, msg) + stats_inc("assertions") + check_msg("assert_string", msg) + do_assert(is_string(actual), "string expected but was a "..type(actual), msg) + return actual +end + + +function assert_not_string(actual, msg) + stats_inc("assertions") + check_msg("assert_not_string", msg) + do_assert(not is_string(actual), "string not expected but was one", msg) + return actual +end + + +function assert_table(actual, msg) + stats_inc("assertions") + check_msg("assert_table", msg) + do_assert(is_table(actual), "table expected but was a "..type(actual), msg) + return actual +end + + +function assert_not_table(actual, msg) + stats_inc("assertions") + check_msg("assert_not_table", msg) + do_assert(not is_table(actual), "table not expected but was one", msg) + return actual +end + + +function assert_function(actual, msg) + stats_inc("assertions") + check_msg("assert_function", msg) + do_assert(is_function(actual), "function expected but was a "..type(actual), msg) + return actual +end + + +function assert_not_function(actual, msg) + stats_inc("assertions") + check_msg("assert_not_function", msg) + do_assert(not is_function(actual), "function not expected but was one", msg) + return actual +end + + +function assert_thread(actual, msg) + stats_inc("assertions") + check_msg("assert_thread", msg) + do_assert(is_thread(actual), "thread expected but was a "..type(actual), msg) + return actual +end + + +function assert_not_thread(actual, msg) + stats_inc("assertions") + check_msg("assert_not_thread", msg) + do_assert(not is_thread(actual), "thread not expected but was one", msg) + return actual +end + + +function assert_userdata(actual, msg) + stats_inc("assertions") + check_msg("assert_userdata", msg) + do_assert(is_userdata(actual), "userdata expected but was a "..type(actual), msg) + return actual +end + + +function assert_not_userdata(actual, msg) + stats_inc("assertions") + check_msg("assert_not_userdata", msg) + do_assert(not is_userdata(actual), "userdata not expected but was one", msg) + return actual +end + + +function assert_error(msg, func) + stats_inc("assertions") + if is_nil(func) then func, msg = msg, nil end + check_msg("assert_error", msg) + do_assert(is_function(func), "assert_error expects a function as the last argument but it was a "..type(func)) + local ok, errmsg = pcall(func) + do_assert(ok == false, "error expected but no error occurred", msg) +end + + +function assert_pass(msg, func) + stats_inc("assertions") + if is_nil(func) then func, msg = msg, nil end + check_msg("assert_pass", msg) + do_assert(is_function(func), "assert_pass expects a function as the last argument but it was a "..type(func)) + local ok, errmsg = pcall(func) + if not ok then do_assert(ok == true, "no error expected but error was: "..errmsg, msg) end +end + + + + +----------------------------------------------------------- +-- Assert implementation that assumes it was called from -- +-- lunit code which was called directly from user code. -- +----------------------------------------------------------- + +function do_assert(assertion, base_msg, user_msg) + orig_assert(is_boolean(assertion)) + orig_assert(is_string(base_msg)) + orig_assert(is_string(user_msg) or is_nil(user_msg)) + if not assertion then + if user_msg then + error(base_msg..": "..user_msg, 3) + else + error(base_msg.."!", 3) + end + end +end + +------------------------------------------- +-- Checks the msg argument in assert_xxx -- +------------------------------------------- + +function check_msg(name, msg) + orig_assert(is_string(name)) + if not (is_nil(msg) or is_string(msg)) then + error("lunit."..name.."() expects the optional message as a string but it was a "..type(msg).."!" ,3) + end +end + + + + +------------------------------------- +-- Creates a new TestCase 'Object' -- +------------------------------------- + +function TestCase(name) + do_assert(is_string(name), "lunit.TestCase() needs a string as an argument") + local tc = { + __lunit_name = name; + __lunit_setup = nil; + __lunit_tests = { }; + __lunit_teardown = nil; + } + setmetatable(tc, tc_mt) + table.insert(testcases, tc) + return tc +end + +tc_mt = { + __newindex = function(tc, key, value) + rawset(tc, key, value) + if is_string(key) and is_function(value) then + local name = string.lower(key) + if string.find(name, "^test") or string.find(name, "test$") then + table.insert(tc.__lunit_tests, key) + elseif name == "setup" then + tc.__lunit_setup = value + elseif name == "teardown" then + tc.__lunit_teardown = value + end + end + end +} + + + +----------------------------------------- +-- Wrap Functions in a TestCase object -- +----------------------------------------- + +function wrap(name, ...) + if is_function(name) then + table.insert(arg, 1, name) + name = "Anonymous Testcase" + end + + local tc = TestCase(name) + for index, test in ipairs(arg) do + tc["Test #"..index] = test + end + return tc +end + + + + + + +---------------------------------- +-- Runs the complete Test Suite -- +---------------------------------- + +function run() + + --------------------------- + -- Initialize statistics -- + --------------------------- + + stats.testcases = 0 -- Total number of Test Cases + stats.tests = 0 -- Total number of all Tests in all Test Cases + stats.run = 0 -- Number of Tests run + stats.notrun = 0 -- Number of Tests not run + stats.failed = 0 -- Number of Tests failed + stats.warnings = 0 -- Number of Warnings (teardown) + stats.errors = 0 -- Number of Errors (setup) + stats.passed = 0 -- Number of Test passed + stats.assertions = 0 -- Number of all assertions made in all Test in all Test Cases + + -------------------------------- + -- Count Test Cases and Tests -- + -------------------------------- + + stats.testcases = table.getn(testcases) + + for _, tc in ipairs(testcases) do + stats_inc("tests" , table.getn(tc.__lunit_tests)) + end + + ------------------ + -- Print Header -- + ------------------ + + print() + print("#### Test Suite with "..stats.tests.." Tests in "..stats.testcases.." Test Cases loaded.") + + ------------------------ + -- Run all Test Cases -- + ------------------------ + + for _, tc in ipairs(testcases) do + run_testcase(tc) + end + + ------------------ + -- Print Footer -- + ------------------ + + print() + print("#### Test Suite finished.") + + local msg_assertions = stats.assertions.." Assertions checked. " + local msg_passed = stats.passed == stats.tests and "All Tests passed" or stats.passed.." Tests passed" + local msg_failed = stats.failed > 0 and ", "..stats.failed.." failed" or "" + local msg_run = stats.notrun > 0 and ", "..stats.notrun.." not run" or "" + local msg_warn = stats.warnings > 0 and ", "..stats.warnings.." warnings" or "" + + print() + print(msg_assertions..msg_passed..msg_failed..msg_run..msg_warn.."!") + + ----------------- + -- Return code -- + ----------------- + + if stats.passed == stats.tests then + return 0 + else + return 1 + end +end + + + + +----------------------------- +-- Runs a single Test Case -- +----------------------------- + +function run_testcase(tc) + + orig_assert(is_table(tc)) + orig_assert(is_table(tc.__lunit_tests)) + orig_assert(is_string(tc.__lunit_name)) + orig_assert(is_nil(tc.__lunit_setup) or is_function(tc.__lunit_setup)) + orig_assert(is_nil(tc.__lunit_teardown) or is_function(tc.__lunit_teardown)) + + ---------------------------------- + -- Protected call to a function -- + ---------------------------------- + + local function call(errprefix, func) + orig_assert(is_string(errprefix)) + orig_assert(is_function(func)) + local ok, errmsg = xpcall(function() func(tc) end, traceback) + if not ok then + print() + print(errprefix..": "..errmsg) + end + return ok + end + + ------------------------------------ + -- Calls setup() on the Test Case -- + ------------------------------------ + + local function setup(testname) + if tc.__lunit_setup then + return call("ERROR: "..testname..": setup() failed", tc.__lunit_setup) + else + return true + end + end + + ------------------------------------------ + -- Calls a single Test on the Test Case -- + ------------------------------------------ + + local function run(testname) + orig_assert(is_string(testname)) + orig_assert(is_function(tc[testname])) + local ok = call("FAIL: "..testname, tc[testname]) + if not ok then + stats_inc("failed") + else + stats_inc("passed") + end + return ok + end + + --------------------------------------- + -- Calls teardown() on the Test Case -- + --------------------------------------- + + local function teardown(testname) + if tc.__lunit_teardown then + if not call("WARNING: "..testname..": teardown() failed", tc.__lunit_teardown) then + stats_inc("warnings") + end + end + end + + --------------------------------- + -- Run all Tests on a TestCase -- + --------------------------------- + + print() + print("#### Running '"..tc.__lunit_name.."' ("..table.getn(tc.__lunit_tests).." Tests)...") + + for _, testname in ipairs(tc.__lunit_tests) do + if setup(testname) then + run(testname) + stats_inc("run") + teardown(testname) + else + print("WARN: Skipping '"..testname.."'...") + stats_inc("notrun") + end + end + +end + + + + +--------------------- +-- Import function -- +--------------------- + +function import(name) + + do_assert(is_string(name), "lunit.import() expects a single string as argument") + + local user_env = getfenv(2) + + -------------------------------------------------- + -- Installs a specific function in the user env -- + -------------------------------------------------- + + local function install(funcname) + user_env[funcname] = P[funcname] + end + + + ---------------------------------------------------------- + -- Install functions matching a pattern in the user env -- + ---------------------------------------------------------- + + local function install_pattern(pattern) + for funcname, _ in pairs(P) do + if string.find(funcname, pattern) then + install(funcname) + end + end + end + + ------------------------------------------------------------ + -- Installs assert() and all assert_xxx() in the user env -- + ------------------------------------------------------------ + + local function install_asserts() + install_pattern("^assert.*") + end + + ------------------------------------------- + -- Installs all is_xxx() in the user env -- + ------------------------------------------- + + local function install_tests() + install_pattern("^is_.+") + end + + if name == "asserts" or name == "assertions" then + install_asserts() + elseif name == "tests" or name == "checks" then + install_tests() + elseif name == "all" then + install_asserts() + install_tests() + install("TestCase") + elseif string.find(name, "^assert.*") and P[name] then + install(name) + elseif string.find(name, "^is_.+") and P[name] then + install(name) + elseif name == "TestCase" then + install("TestCase") + else + error("luniit.import(): invalid function '"..name.."' to import", 2) + end +end + + + + +-------------------------------------------------- +-- Installs a private environment on the caller -- +-------------------------------------------------- + +function setprivfenv() + local new_env = { } + local new_env_mt = { __index = getfenv(2) } + setmetatable(new_env, new_env_mt) + setfenv(2, new_env) +end + + + + +-------------------------------------------------- +-- Increments a counter in the statistics table -- +-------------------------------------------------- + +function stats_inc(varname, value) + orig_assert(is_table(stats)) + orig_assert(is_string(varname)) + orig_assert(is_nil(value) or is_number(value)) + if not stats[varname] then return end + stats[varname] = stats[varname] + (value or 1) +end + + + + diff --git a/lua-sqlite3-0.4.1/sqlite3.lua b/lua-sqlite3-0.4.1/sqlite3.lua new file mode 100644 index 0000000..9c2d8f5 --- /dev/null +++ b/lua-sqlite3-0.4.1/sqlite3.lua @@ -0,0 +1,843 @@ + +--[[-------------------------------------------------------------------------- + + Author: Michael Roth + + Copyright (c) 2004, 2005 Michael Roth + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--]]-------------------------------------------------------------------------- + + + + +--[[ + +TODO: + collation set_collation(name, func) + collation_needed set_collation_handler(func) + progress_handler set_progress_handler(func) + authorizer set_auth_handler(func) + commit_hook set_commit_handler(func) + +--]] + + + + + +require "libluasqlite3-loader" + +local api, ERR, TYPE, AUTH = load_libluasqlite3() + +local db_class = { } +local stmt_class = { } + + + + + +local function check_stmt(stmt) + assert(type(stmt.handles) == "table", "Prepared statement expected") + return stmt +end + +local function check_single_stmt(stmt) + assert(type(stmt.handles) == "table" and table.getn(stmt.handles) == 1, "Single prepared statement expected") + return stmt.handles[1] +end + +local function check_db(db) + assert(db.handle, "Open database handle expected") + return db +end + +local function check_table(tab, msg) + assert(type(tab) == "table", msg) + return tab +end + +local function check_string(str, msg) + assert( type(str) == "string", msg ) + return str +end + +local function check_number(num, msg) + assert( type(num) == "number", msg ) + return num +end + + + +----------------------------------------------------- +-- Error test und report helper for sqlite3 errors -- +----------------------------------------------------- + +local function is_error(status) + return not ( status == ERR.OK or status == ERR.ROW or status == ERR.DONE ) +end + +local function is_row(status) + return status == ERR.ROW +end + +local function is_done(status) + return status == ERR.DONE +end + +local function errmsg(db_handle) + return api.errmsg(db_handle) or "Unknown error" +end + + + +------------------------------------------------------------------------- +-- Creates an oject. An object is a table with itself set as metatable -- +------------------------------------------------------------------------- + +local function object() + local t = { } + setmetatable(t, t) + return t +end + + +----------------------------------- +-- Registry for tables (objects) -- +----------------------------------- + +local function create_registry() + return { 0 } +end + +local function register(registry, object) + local id = registry[1] + if id == 0 then + table.insert(registry, object) + return table.getn(registry) + else + registry[1] = registry[id] + registry[id] = object + return id + end +end + +local function unregister(registry, id) + registry[id] = registry[1] + registry[1] = id +end + + + + + +------------- +-- sqlite3 -- +------------- + +sqlite3 = { } + +function sqlite3.open(filename) + check_string(filename, "Filename as string expected") + + local status, handle = api.open(filename) + + if is_error(status) then + local errmsg = errmsg(handle) + api.close(handle) + return nil, errmsg + end + + local db = object() + + db.__gc = db_class.close + db.__index = db_class + db.filename = filename + db.handle = handle + db.stmts = create_registry() + + return db +end + + +function sqlite3.open_memory() + return sqlite3.open(":memory:") +end + + + +-------------------- +-- Database Class -- +-------------------- + +function db_class.close(db) + check_db(db) + + for _, obj in ipairs(db.stmts) do + if type(obj) == "table" then + obj:close() + end + end + + local status = api.close(db.handle) + + if is_error(status) then + return nil, errmsg(db.handle) + end + + db.handle = nil + db.stmts = nil + db.__gc = nil + + return db +end + + +function db_class.interrupt(db) + check_db(db) + + local status = api.interrupt(db.handle) + + if is_error(status) then + return nil, errmsg(db.handle) + end + + return db +end + + +function db_class.last_insert_rowid(db) + check_db(db) + return api.last_insert_rowid(db.handle) +end + + +function db_class.changes(db) + check_db(db) + return api.changes(db.handle) +end + + +function db_class.total_changes(db) + check_db(db) + return api.total_changes(db.handle) +end + + +function db_class.exec(db, sql) + check_db(db) + check_string(sql) + + local status = api.exec(db.handle, sql) + + if is_error(status) then + return nil, errmsg(db.handle) + end + + return db +end + + +function db_class.irows(db, sql, tab) + check_db(db) + return db:prepare(sql):irows(tab, true) +end + + +function db_class.rows(db, sql, tab) + check_db(db) + return db:prepare(sql):rows(tab, true) +end + + +function db_class.cols(db, sql) + check_db(db) + return db:prepare(sql):cols(true) +end + + +function db_class.first_irow(db, sql, tab) + check_db(db) + return db:prepare(sql):first_irow(tab, true) +end + + +function db_class.first_row(db, sql, tab) + check_db(db) + return db:prepare(sql):first_row(tab, true) +end + + +function db_class.first_cols(db, sql) + check_db(db) + return db:prepare(sql):first_cols(true) +end + + +function db_class.prepare(db, paranames, sql) + check_db(db) + + if sql == nil then + sql = paranames + paranames = nil + end + + check_string(sql, "db:prepare: SQL statement as string expected") + + local function cleanup(handles) + for _, handle in ipairs(handles) do + api.finalize(handle) + end + end + + local function count_parameters(handles) + local parameter_count = 0 + for _, handle in ipairs(handles) do + parameter_count = parameter_count + api.bind_parameter_count(handle) + end + return parameter_count + end + + local function build_handles(sql) + local status, handle + local remaining = sql + local handles = { } + + while remaining do + status, handle, remaining = api.prepare(db.handle, remaining) + + if is_error(status) then + local errmsg = errmsg(db.handle) + cleanup(handles) + return nil, errmsg + end + + table.insert(handles, handle) + end + + return handles + end + + local function anonymous_parameters(handles) + for _, handle in ipairs(handles) do + for i = 1, api.bind_parameter_count(handle) do + if api.bind_parameter_name_x(handle, i) then + return false + end + end + end + return true + end + + local function named_parameters(handles) + for _, handle in ipairs(handles) do + for i = 1, api.bind_parameter_count(handle) do + if not api.bind_parameter_name_x(handle, i) then + return false + end + end + end + return true + end + + local function create_mapping(handles, paranames) + local invers = { } + + for index, name in ipairs(paranames) do + invers[name] = index + end + + local mapping = { } + + for _, handle in ipairs(handles) do + for index = 1, api.bind_parameter_count(handle) do + local parameter_name = api.bind_parameter_name_x(handle, index) + local pos = invers[parameter_name] + if pos == nil then + cleanup(handles) + return nil, "db:prepare: Unknown parameter name '" .. parameter_name .. "'in statement." + end + table.insert(mapping, pos) + end + end + + return mapping + end + + local function collect_parameter_names(handles) + local seen = { } + local names = { } + + for _, handle in ipairs(handles) do + for index = 1, api.bind_parameter_count(handle) do + local parameter_name = api.bind_parameter_name_x(handle, index) + if not seen[parameter_name] then + table.insert(names, parameter_name) + seen[parameter_name] = true + end + end + end + + return names + end + + local function fix_parameter_names(unfixed_parameters) + local fixed_parameters = { } + for _, unfixed_name in ipairs(unfixed_parameters) do + local _, _, fixed_name = string.find(unfixed_name, "^[:$]?(%a%w*)$") + if not fixed_name then + return nil, "db:prepare: Invalid parameter name: '" .. unfixed_name .."'." + end + table.insert(fixed_parameters, fixed_name) + end + return fixed_parameters + end + + local function create_stmt(db, handles, parameter_count) + local stmt = object() + stmt.__gc = stmt_class.close + stmt.__index = stmt_class + stmt.handles = handles + stmt.db = db + stmt.reg_id = register(db.stmts, stmt) + stmt.parameter_count= parameter_count + return stmt + end + + local handles, errmsg = build_handles(sql) + + if errmsg then + return nil, errmsg + end + + local parameter_count = count_parameters(handles) + + if parameter_count == 0 then -- No parameters at all + return create_stmt(db, handles, 0) + else + if anonymous_parameters(handles) then -- All parameters are anonymous ("?") + + return create_stmt(db, handles, parameter_count) + + elseif named_parameters(handles) then -- All parameters are named (":foobar" & "$foobar") + + if paranames then -- Fixed mapping of parameter names + + check_table(paranames, "db:prepare: Names of parameters expected as strings") + + local fixed_parameter_names, errmsg = fix_parameter_names(paranames) + + if errmsg then + cleanup(handles) + return nil, errmgs + end + + local mapping, errmsg = create_mapping(handles, fixed_parameter_names) + + if errmsg then + cleanup(handles) + return nil, errmsg + end + + local stmt = create_stmt(db, handles, table.getn(fixed_parameter_names)) + stmt.mapping = mapping + stmt.paranames = fixed_parameter_names + + return stmt + + else -- Automatic mapping of paramter names + + local parameter_names = collect_parameter_names(handles) + local mapping = create_mapping(handles, parameter_names) + local stmt = create_stmt(db, handles, table.getn(parameter_names)) + stmt.mapping = mapping + stmt.paranames = parameter_names + + return stmt + + end + + else -- Mixed paramters are not allowed + + cleanup(handles) + return nil, "db:prepare: Mixed anonymous and named parameters are not allowed." + + end + end +end + + +local function call_user_func(context, func, num_values, values) + -- Don't use table.insert() because of nils in lua-5.1 + local arg = { } + for index = 1, num_values do + arg[index] = api.value(values, index-1) + end + -- Make lua-5.0.2 unpack() happy + arg.n = num_values + -- lua-5.1 unpack() style / lua-5.0.2 ignores additional arguments + local ok, result = pcall(func, unpack(arg, 1, num_values)) + + if not ok then + api.result_error(context, tostring(result)) + else + api.result(context, result) + end +end + + +function db_class.set_function(db, name, num_args, func) + check_db(db) + + local function xfunc(context, num_values, values) + call_user_func(context, func, num_values, values) + end + + local status = api.create_function(db.handle, name, num_args, xfunc, nil, nil) + + if is_error(status) then + return nil, errmsg(db.handle) + end + + return db +end + + +function db_class.set_aggregate(db, name, num_args, create_funcs) + check_db(db) + + local step, final + + local function xstep(context, num_values, values) + if not step and not final then + step, final = create_funcs() + end + call_user_func(context, step, num_values, values) + end + + local function xfinal(context) + local ok, result = pcall(final, api.aggregate_count(context)) + if not ok then + api.result_error(context, tostring(result)) + else + api.result(context, result) + end + end + + local status = api.create_function(db.handle, name, num_args, nil, xstep, xfinal) + + if is_error(status) then + return nil, errmsg(db.handle) + end + + return db +end + + +function db_class.set_trace_handler(db, func) + check_db(db) + local status = api.trace(db.handle, func) + if is_error(status) then + return nil, errmsg(db.handle) + end + return db +end + + +function db_class.set_busy_timeout(db, ms) + check_db(db) + local status = api.busy_timeout(db.handle, ms) + if is_error(status) then + return nil, errmsg(db.handle) + end + return db +end + + +function db_class.set_busy_handler(db, func) + check_db(db) + local status = api.busy_handler(db.handle, func) + if is_error(status) then + return nil, errmsg(db.handle) + end + return db +end + + + + + +--------------------- +-- Statement Class -- +--------------------- + +function stmt_class.bind(stmt, ...) + + local function bind_with_mapping(parameters) + local mapping = stmt.mapping + local map_index = 1 + for _, handle in ipairs(stmt.handles) do + for index = 1, api.bind_parameter_count(handle) do + local status = api.bind(handle, index, parameters[mapping[map_index]]) + if is_error(status) then + return nil, errmsg(stmt.db.handle) + end + map_index = map_index + 1 + end + end + end + + local function bind_without_mapping(parameters) + local parameter_index = 1 + for _, handle in ipairs(stmt.handles) do + for index = 1, api.bind_parameter_count(handle) do + local status = api.bind(handle, index, parameters[parameter_index]) + if is_error(status) then + return nil, errmsg(stmt.db.handle) + end + parameter_index = parameter_index + 1 + end + end + end + + local function bind_by_names(parameters) + local parameter_names = stmt.paranames + local mapping = stmt.mapping + for _, handle in ipairs(stmt.handles) do + for index = 1, api.bind_parameter_count(handle) do + local status = api.bind(handle, index, parameters[parameter_names[mapping[index]]]) + if is_error(status) then + return nil, errmsg(stmt.db.handle) + end + end + end + end + + check_stmt(stmt) + if stmt.parameter_count == 0 then error("stmt:bind: statement contains no parameters.") end + + if type(arg[1]) == "table" and arg.n == 1 and stmt.mapping and stmt.paranames then + bind_by_names(arg[1]) + else + if arg.n < stmt.parameter_count then error("stmt:bind: to few parameters.") end + if arg.n > stmt.parameter_count then error("stmt:bind: to many parameters.") end + + if stmt.mapping then + bind_with_mapping(arg) + else + bind_without_mapping(arg) + end + end + + return stmt +end + + +function stmt_class.reset(stmt) + check_stmt(stmt) + for _, handle in ipairs(stmt.handles) do + api.reset(handle) + end + return stmt +end + + +function stmt_class.close(stmt) + check_stmt(stmt) + + for _, handle in ipairs(stmt.handles) do + api.finalize(handle) + end + + unregister(stmt.db.stmts, stmt.reg_id) + + stmt.db = nil + stmt.handles = nil + stmt.mapping = nil + stmt.__gc = nil + + return stmt +end + + +local no_parameter_names = { } +function stmt_class.parameter_names(stmt) + check_stmt(stmt) + if not stmt.paranames then + return no_parameter_names + else + return stmt.paranames + end +end + + +local function stmt_column_info(stmt, info_func) + local handle = check_single_stmt(stmt) + local info = { } + for index = 1, api.column_count(handle) do + table.insert(info, info_func(handle, index-1) ) + end + return info +end + +function stmt_class.column_names(stmt) + return stmt_column_info(stmt, api.column_name) +end + +function stmt_class.column_decltypes(stmt) + return stmt_column_info(stmt, api.column_decltype) +end + + +function stmt_class.column_count(stmt) + local handle = check_single_stmt(stmt) + return api.column_count(handle) +end + + +function stmt_class.exec(stmt) + check_stmt(stmt) + stmt:reset() + for _, handle in ipairs(stmt.handles) do + while true do + local status = api.step(handle) + + if is_error(status) then + local errmsg = errmsg(stmt.db.handle) + api.reset(handle) + return nil, errmsg + end + + if is_done(status) then + break + end + end + api.reset(handle) + end + return stmt +end + + +local function stmt_rows(stmt, get_row_func, tab, autoclose) + local handle = check_single_stmt(stmt) + api.reset(handle) + + local function check_autoclose() + if autoclose == true then + stmt:close() + else + api.reset(handle) + end + end + + local iterator = function() + local status = api.step(handle) + + if is_error(status) then + local errmsg = errmsg(stmt.db.handle) + check_autoclose() + return nil, errmsg + end + + if is_row(status) then + return get_row_func(handle, tab) + end + + if is_done(status) then + check_autoclose() + return nil + end + + return nil, "stmt:rows: Internal error!" + end + + return iterator +end + +function stmt_class.irows(stmt, tab, autoclose) + return stmt_rows(stmt, api.irow, tab, autoclose) +end + +function stmt_class.rows(stmt, tab, autoclose) + return stmt_rows(stmt, api.arow, tab, autoclose) +end + +function stmt_class.cols(stmt, autoclose) + return stmt_rows(stmt, api.drow, nil, autoclose) +end + + +local function first_row(stmt, get_row_func, tab, autoclose) + local handle = check_single_stmt(stmt) + api.reset(handle) + + local function check_autoclose() + if autoclose == true then + stmt:close() + else + api.reset(handle) + end + end + + local status = api.step(handle) + + if is_error(status) then + local errmsg = errmsg(stmt.db.handle) + check_autoclose() + return nil, errmsg + end + + if is_row(status) then + local row = get_row_func(handle, tab) + check_autoclose() + return row + end + + if is_done(status) then + check_autoclose() + return nil, "No row returned." + end + + return nil, "stmt:first_row: Internal error!" + +end + +function stmt_class.first_irow(stmt, tab, autoclose) + return first_row(stmt, api.irow, tab, autoclose) +end + +function stmt_class.first_row(stmt, tab, autoclose) + return first_row(stmt, api.arow, tab, autoclose) +end + +function stmt_class.first_cols(stmt, autoclose) + local count = api.column_count(stmt.handles[1]) + local row, errmsg = first_row(stmt, api.irow, nil, autoclose) + if errmsg then + return nil, errmsg + else + row.n = count -- Make lua-5.0.2 unpack() happy + return unpack(row, 1, count) -- lua-5.1 style / lua-5.0.2 ignores additional arguments + end +end + + + diff --git a/lua-sqlite3-0.4.1/tests-luasql.lua b/lua-sqlite3-0.4.1/tests-luasql.lua new file mode 100644 index 0000000..ae393a8 --- /dev/null +++ b/lua-sqlite3-0.4.1/tests-luasql.lua @@ -0,0 +1,241 @@ + +--[[-------------------------------------------------------------------------- + + Author: Michael Roth + + Copyright (c) 2004 Michael Roth + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--]]-------------------------------------------------------------------------- + + + + +------------------------------------------------- +-- This is the luaSql compatible sqlite driver -- +------------------------------------------------- +require "luasql-sqlite3" + +require "lunit" + +lunit.setprivfenv() +lunit.import "asserts" + + + + +lunit.wrap("Driver Interface", function() + assert_table( luasql ) + assert_function( luasql.sqlite3 ) + local env = assert_table( luasql.sqlite3() ) + assert_function( env.connect ) + assert_function( env.connect_memory ) -- sqlite3 extension + assert_function( env.close ) + assert_true( env:close(), "Closing an unused environment must return 'true'" ) + assert_nil( env:close(), "Closing a closed environment must return 'nil'" ) +end) + + + +lunit.wrap("Connection Interface", function() + local env = assert_table( luasql.sqlite3() ) + local con = assert_table( env:connect_memory() ) + assert_function( con.close ) + assert_function( con.execute ) + assert_function( con.rollback ) + assert_function( con.commit ) + assert_function( con.setautocommit ) + assert_true( con:close(), "Closing an open connection must return 'true'" ) + assert_nil( con:close(), "Closing a closed connection must return 'nil'" ) + assert_true( env:close() ) +end) + + + +lunit.wrap("Simple connection usage", function() + local env = assert_table( luasql.sqlite3() ) + local con = assert_table( env:connect_memory() ) + assert_equal( 0, con:execute("CREATE TABLE test (id, name)") ) + assert_equal( 1, con:execute("INSERT INTO test VALUES (1, 'Hello World')") ) + assert_true( con:close() ) + assert_true( env:close() ) +end) + + + +lunit.wrap("Cursor Interface", function() + local env = assert_table( luasql.sqlite3() ) + local con = assert_table( env:connect_memory() ) + assert_equal( 0, con:execute("CREATE TABLE test (id, name)") ) + local cur = assert_table( con:execute("SELECT * FROM test") ) + assert_function( cur.close ) + assert_function( cur.fetch ) + assert_function( cur.getcolnames ) + assert_function( cur.getcoltypes ) + assert_true( cur:close(), "Closing an open cursor must return 'true'" ) + assert_nil( cur:close(), "Closing a closed cursor must return 'nil'" ) + assert_true( con:close() ) + assert_true( env:close() ) +end) + + + +local scu = lunit.TestCase("Simple cursor usage") + +function scu:setup() + -- open database + self.env = assert_table( luasql.sqlite3() ) + self.con = assert_table( self.env:connect_memory() ) + + -- prepare database + assert_equal( 0, self.con:execute("CREATE TABLE test (id INTEGER, item TEXT)") ) + assert_equal( 1, self.con:execute("INSERT INTO test VALUES (1, 'Hello World')") ) + assert_equal( 1, self.con:execute("INSERT INTO test VALUES (2, 'Hello Lua')") ) + assert_equal( 1, self.con:execute("INSERT INTO test VALUES (3, 'Hello sqlite3')") ) + + -- open cursor + self.cur = assert_table( self.con:execute("SELECT * FROM test ORDER BY id") ) +end + +function scu:teardown() + assert_true( self.cur:close() ) + assert_true( self.con:close() ) + assert_true( self.env:close() ) +end + +function scu:test_fetch_direct() + local id, item + id, item = self.cur:fetch(); assert_equal(1, id); assert_equal("Hello World", item) + id, item = self.cur:fetch(); assert_equal(2, id); assert_equal("Hello Lua", item) + id, item = self.cur:fetch(); assert_equal(3, id); assert_equal("Hello sqlite3", item) + assert_nil( self.cur:fetch() ) +end + +function scu.check(key_id, id, key_item, item, row) + assert_table(row) + assert_equal(id, row[key_id]) + assert_equal(item, row[key_item]) +end + +function scu:test_fetch_default() + self.check(1, 1, 2, "Hello World", self.cur:fetch({}) ) + self.check(1, 2, 2, "Hello Lua", self.cur:fetch({}) ) + self.check(1, 3, 2, "Hello sqlite3", self.cur:fetch({}) ) + assert_nil( self.cur:fetch({}) ) +end + +function scu:test_fetch_numeric() + self.check(1, 1, 2, "Hello World", self.cur:fetch({}, "n") ) + self.check(1, 2, 2, "Hello Lua", self.cur:fetch({}, "n") ) + self.check(1, 3, 2, "Hello sqlite3", self.cur:fetch({}, "n") ) + assert_nil( self.cur:fetch({}, "n") ) +end + +function scu:test_fetch_alphanumeric() + self.check("id", 1, "item", "Hello World", self.cur:fetch({}, "a")) + self.check("id", 2, "item", "Hello Lua", self.cur:fetch({}, "a")) + self.check("id", 3, "item", "Hello sqlite3", self.cur:fetch({}, "a")) + assert_nil( self.cur:fetch({}, "a") ) +end + +function scu:test_getcolnames() + local names = assert_table( self.cur:getcolnames() ) + assert_equal(2, table.getn(names) ) + assert_equal("id", names[1]) + assert_equal("item", names[2]) +end + +function scu:test_getcoltypes() + local types = assert_table( self.cur:getcoltypes() ) + assert_equal(2, table.getn(types) ) + assert_equal("INTEGER", types[1]) + assert_equal("TEXT", types[2]) +end + + + +local ta = lunit.TestCase("Transaction Tests") + +function ta:setup() + -- open database + self.env = assert_table( luasql.sqlite3() ) + self.con = assert_table( self.env:connect_memory() ) + + -- prepare database + assert_equal( 0, self.con:execute("CREATE TABLE test (id INTEGER, item TEXT)") ) + assert_equal( 1, self.con:execute("INSERT INTO test VALUES (1, 'Hello World')") ) + assert_equal( 1, self.con:execute("INSERT INTO test VALUES (2, 'Hello Lua')") ) + assert_equal( 1, self.con:execute("INSERT INTO test VALUES (3, 'Hello sqlite3')") ) + + -- switch to manual transaction controll + assert_true( self.con:setautocommit(false) ) +end + +function ta:teardown() + assert_true( self.con:close() ) + assert_true( self.env:close() ) +end + +function ta:insert(id, item) + assert_equal(1, self.con:execute("INSERT INTO test VALUES ("..id..", '"..item.."')") ) +end + +function ta:update(id, item) + assert_equal(1, self.con:execute("UPDATE test SET item = '"..item.."' WHERE id = "..id) ) +end + +function ta:check(expected) + assert_table(expected) + + local cur = assert_table( self.con:execute("SELECT * FROM test ORDER BY id") ) + local id = 0 + local row = cur:fetch({}, "a") + while row do + assert_table(row) + id = id + 1 + assert_equal(id, row.id, "Unexpected 'id' read (wrong row?)") + assert( id <= table.getn(expected), "'Id' read to large (to many rows?)") + assert_equal(expected[id], row.item, "Invalid content in row") + row = cur:fetch({}, "a") + end + assert_equal(id, table.getn(expected), "To less rows read") + assert_true( cur:close() ) +end + +function ta:test_prepared_content() + self:check { "Hello World", "Hello Lua", "Hello sqlite3" } +end + +function ta:test_transactions() + self:insert(4, "Hello again") + self:insert(5, "Goodbye") + self:check { "Hello World", "Hello Lua", "Hello sqlite3", "Hello again", "Goodbye" } + assert_true( self.con:commit() ) + self:update(1, "Good morning") + self:insert(6, "Foobar") + self:check { "Good morning", "Hello Lua", "Hello sqlite3", "Hello again", "Goodbye", "Foobar" } + assert_true( self.con:rollback() ) + self:check { "Hello World", "Hello Lua", "Hello sqlite3", "Hello again", "Goodbye" } +end + + + + diff --git a/lua-sqlite3-0.4.1/tests-sqlite3.lua b/lua-sqlite3-0.4.1/tests-sqlite3.lua new file mode 100644 index 0000000..133cf91 --- /dev/null +++ b/lua-sqlite3-0.4.1/tests-sqlite3.lua @@ -0,0 +1,472 @@ + +--[[-------------------------------------------------------------------------- + + Author: Michael Roth + + Copyright (c) 2004, 2005 Michael Roth + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--]]-------------------------------------------------------------------------- + + +require "sqlite3" + +require "lunit" + +lunit.setprivfenv() +lunit.import "assertions" +lunit.import "checks" + + + + + + +------------------------------- +-- Basic open and close test -- +------------------------------- + +lunit.wrap("open_memory", function() + local db = assert_table( sqlite3.open_memory() ) + assert( db:close() ) +end) + +lunit.wrap("open", function() + local filename = "/tmp/__lua-sqlite3-20040906135849." .. os.time() + local db = assert_table( sqlite3.open(filename) ) + assert( db:close() ) + os.remove(filename) +end) + + + +------------------------------------- +-- Presence of db member functions -- +------------------------------------- + +local db_funcs = lunit.TestCase("Database Member Functions") + +function db_funcs:setup() + self.db = assert( sqlite3.open_memory() ) +end + +function db_funcs:teardown() + assert( self.db:close() ) +end + +function db_funcs:test() + local db = self.db + assert_function( db.close ) + assert_function( db.exec ) + assert_function( db.irows ) + assert_function( db.rows ) + assert_function( db.cols ) + assert_function( db.first_irow ) + assert_function( db.first_row ) + assert_function( db.first_cols ) + assert_function( db.prepare ) + assert_function( db.interrupt ) + assert_function( db.last_insert_rowid ) + assert_function( db.changes ) + assert_function( db.total_changes ) +end + + + +--------------------------------------- +-- Presence of stmt member functions -- +--------------------------------------- + +local stmt_funcs = lunit.TestCase("Statement Member Functions") + +function stmt_funcs:setup() + self.db = assert( sqlite3.open_memory() ) + self.stmt = assert( self.db:prepare("CREATE TABLE test (id, content)") ) +end + +function stmt_funcs:teardown() + assert( self.stmt:close() ) + assert( self.db:close() ) +end + +function stmt_funcs:test() + local stmt = self.stmt + assert_function( stmt.close ) + assert_function( stmt.reset ) + assert_function( stmt.exec ) + assert_function( stmt.bind ) + assert_function( stmt.irows ) + assert_function( stmt.rows ) + assert_function( stmt.cols ) + assert_function( stmt.first_irow ) + assert_function( stmt.first_row ) + assert_function( stmt.first_cols ) + assert_function( stmt.column_names ) + assert_function( stmt.column_decltypes ) + assert_function( stmt.column_count ) +end + + + +------------------ +-- Tests basics -- +------------------ + +local basics = lunit.TestCase("Basics") + +function basics:setup() + self.db = assert_table( sqlite3.open_memory() ) +end + +function basics:teardown() + assert_table( self.db:close() ) +end + +function basics:create_table() + assert_table( self.db:exec("CREATE TABLE test (id, name)") ) +end + +function basics:drop_table() + assert_table( self.db:exec("DROP TABLE test") ) +end + +function basics:insert(id, name) + assert_table( self.db:exec("INSERT INTO test VALUES ("..id..", '"..name.."')") ) +end + +function basics:update(id, name) + assert_table( self.db:exec("UPDATE test SET name = '"..name.."' WHERE id = "..id) ) +end + +function basics:test_create_drop() + self:create_table() + self:drop_table() +end + +function basics:test_multi_create_drop() + self:create_table() + self:drop_table() + self:create_table() + self:drop_table() +end + +function basics:test_insert() + self:create_table() + self:insert(1, "Hello World") + self:insert(2, "Hello Lua") + self:insert(3, "Hello sqlite3") +end + +function basics:test_update() + self:create_table() + self:insert(1, "Hello Home") + self:insert(2, "Hello Lua") + self:update(1, "Hello World") +end + + +--------------------------------- +-- Statement Column Info Tests -- +--------------------------------- + +lunit.wrap("Column Info Test", function() + local db = assert_table( sqlite3.open_memory() ) + assert_table( db:exec("CREATE TABLE test (id INTEGER, name TEXT)") ) + local stmt = assert_table( db:prepare("SELECT * FROM test") ) + + assert_equal(2, stmt:column_count(), "Wrong number of columns." ) + + local names = assert_table( stmt:column_names() ) + assert_equal(2, table.getn(names), "Wrong number of names.") + assert_equal("id", names[1] ) + assert_equal("name", names[2] ) + + local types = assert_table( stmt:column_decltypes() ) + assert_equal(2, table.getn(types), "Wrong number of declaration types.") + assert_equal("INTEGER", types[1] ) + assert_equal("TEXT", types[2] ) + + assert_table( stmt:close() ) + assert_table( db:close() ) +end) + + + +--------------------- +-- Statement Tests -- +--------------------- + +st = lunit.TestCase("Statement Tests") + +function st:setup() + self.db = assert( sqlite3.open_memory() ) + assert_table( self.db:exec("CREATE TABLE test (id, name)") ) + assert_table( self.db:exec("INSERT INTO test VALUES (1, 'Hello World')") ) + assert_table( self.db:exec("INSERT INTO test VALUES (2, 'Hello Lua')") ) + assert_table( self.db:exec("INSERT INTO test VALUES (3, 'Hello sqlite3')") ) +end + +function st:teardown() + assert_table( self.db:close() ) +end + +function st:check_content(expected) + local stmt = assert( self.db:prepare("SELECT * FROM test ORDER BY id") ) + local i = 0 + for row in stmt:irows() do + i = i + 1 + assert( i <= table.getn(expected), "To much rows." ) + assert_equal(2, table.getn(row), "Two result column expected.") + assert_equal(i, row[1], "Wrong 'id'.") + assert_equal(expected[i], row[2], "Wrong 'name'.") + end + assert_equal( table.getn(expected), i, "To few rows." ) + assert_table( stmt:close() ) +end + +function st:test_setup() + assert_pass(function() self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3" } end) + assert_error(function() self:check_content{ "Hello World", "Hello Lua" } end) + assert_error(function() self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "To much" } end) + assert_error(function() self:check_content{ "Hello World", "Hello Lua", "Wrong" } end) + assert_error(function() self:check_content{ "Hello World", "Wrong", "Hello sqlite3" } end) + assert_error(function() self:check_content{ "Wrong", "Hello Lua", "Hello sqlite3" } end) +end + +function st:test_questionmark_args() + local stmt = assert_table( self.db:prepare("INSERT INTO test VALUES (?, ?)") ) + assert_table( stmt:bind(0, "Test") ) + assert_error(function() stmt:bind("To few") end) + assert_error(function() stmt:bind(0, "Test", "To many") end) +end + +function st:test_questionmark() + local stmt = assert_table( self.db:prepare("INSERT INTO test VALUES (?, ?)") ) + assert_table( stmt:bind(4, "Good morning") ) + assert_table( stmt:exec() ) + self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning" } + assert_table( stmt:bind(5, "Foo Bar") ) + assert_table( stmt:exec() ) + self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning", "Foo Bar" } +end + +function st:test_questionmark_multi() + local stmt = assert_table( self.db:prepare([[ + INSERT INTO test VALUES (?, ?); INSERT INTO test VALUES (?, ?) ]])) + assert( stmt:bind(5, "Foo Bar", 4, "Good morning") ) + assert( stmt:exec() ) + self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning", "Foo Bar" } +end + +function st:test_identifiers() + local stmt = assert_table( self.db:prepare("INSERT INTO test VALUES (:id, :name)") ) + assert_table( stmt:bind(4, "Good morning") ) + assert_table( stmt:exec() ) + self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning" } + assert_table( stmt:bind(5, "Foo Bar") ) + assert_table( stmt:exec() ) + self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning", "Foo Bar" } +end + +function st:test_identifiers_multi() + local stmt = assert_table( self.db:prepare([[ + INSERT INTO test VALUES (:id1, :name1); INSERT INTO test VALUES (:id2, :name2) ]])) + assert( stmt:bind(5, "Foo Bar", 4, "Good morning") ) + assert( stmt:exec() ) + self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning", "Foo Bar" } +end + +function st:test_identifiers_names() + local stmt = assert_table( self.db:prepare({"name", "id"}, "INSERT INTO test VALUES (:id, $name)") ) + assert_table( stmt:bind("Good morning", 4) ) + assert_table( stmt:exec() ) + self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning" } + assert_table( stmt:bind("Foo Bar", 5) ) + assert_table( stmt:exec() ) + self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning", "Foo Bar" } +end + +function st:test_identifiers_multi_names() + local stmt = assert_table( self.db:prepare( {"name", "id1", "id2"},[[ + INSERT INTO test VALUES (:id1, $name); INSERT INTO test VALUES ($id2, :name) ]])) + assert( stmt:bind("Hoho", 4, 5) ) + assert( stmt:exec() ) + self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Hoho", "Hoho" } +end + +function st:test_colon_identifiers_names() + local stmt = assert_table( self.db:prepare({":name", ":id"}, "INSERT INTO test VALUES (:id, $name)") ) + assert_table( stmt:bind("Good morning", 4) ) + assert_table( stmt:exec() ) + self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning" } + assert_table( stmt:bind("Foo Bar", 5) ) + assert_table( stmt:exec() ) + self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning", "Foo Bar" } +end + +function st:test_colon_identifiers_multi_names() + local stmt = assert_table( self.db:prepare( {":name", ":id1", ":id2"},[[ + INSERT INTO test VALUES (:id1, $name); INSERT INTO test VALUES ($id2, :name) ]])) + assert( stmt:bind("Hoho", 4, 5) ) + assert( stmt:exec() ) + self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Hoho", "Hoho" } +end + +function st:test_dollar_identifiers_names() + local stmt = assert_table( self.db:prepare({"$name", "$id"}, "INSERT INTO test VALUES (:id, $name)") ) + assert_table( stmt:bind("Good morning", 4) ) + assert_table( stmt:exec() ) + self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning" } + assert_table( stmt:bind("Foo Bar", 5) ) + assert_table( stmt:exec() ) + self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning", "Foo Bar" } +end + +function st:test_dollar_identifiers_multi_names() + local stmt = assert_table( self.db:prepare( {"$name", "$id1", "$id2"},[[ + INSERT INTO test VALUES (:id1, $name); INSERT INTO test VALUES ($id2, :name) ]])) + assert( stmt:bind("Hoho", 4, 5) ) + assert( stmt:exec() ) + self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Hoho", "Hoho" } +end + + +function st:test_bind_by_names() + local stmt = assert_table( self.db:prepare("INSERT INTO test VALUES (:id, :name)") ) + local args = { } + args.id = 5 + args.name = "Hello girls" + assert( stmt:bind(args) ) + assert( stmt:exec() ) + args.id = 4 + args.name = "Hello boys" + assert( stmt:bind(args) ) + assert( stmt:exec() ) + self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Hello boys", "Hello girls" } +end + + + +-------------------------------- +-- Tests binding of arguments -- +-------------------------------- + +b = lunit.TestCase("Binding Tests") + +function b:setup() + self.db = assert( sqlite3.open_memory() ) + assert_table( self.db:exec("CREATE TABLE test (id, name)") ) +end + +function b:teardown() + assert_table( self.db:close() ) +end + +function b:test_auto_parameter_names() + local stmt = assert_table( self.db:prepare([[ + INSERT INTO test VALUES(:a, $b); + INSERT INTO test VALUES(:a2, :b2); + INSERT INTO test VALUES($a, :b); + INSERT INTO test VALUES($a3, $b3) + ]])) + local parameters = assert_table( stmt:parameter_names() ) + assert_equal( 6, table.getn(parameters) ) + assert_equal( "a", parameters[1] ) + assert_equal( "b", parameters[2] ) + assert_equal( "a2", parameters[3] ) + assert_equal( "b2", parameters[4] ) + assert_equal( "a3", parameters[5] ) + assert_equal( "b3", parameters[6] ) +end + +function b:test_no_parameter_names_1() + local stmt = assert_table( self.db:prepare([[ SELECT * FROM test ]])) + local parameters = assert_table( stmt:parameter_names() ) + assert_equal( 0, table.getn(parameters) ) +end + +function b:test_no_parameter_names_2() + local stmt = assert_table( self.db:prepare([[ INSERT INTO test VALUES(?, ?) ]])) + local parameters = assert_table( stmt:parameter_names() ) + assert_equal( 0, table.getn(parameters) ) +end + + + + + + + +-------------------------------------------- +-- Tests loop break and statement reusage -- +-------------------------------------------- + + + +---------------------------- +-- Test for bugs reported -- +---------------------------- + +bug = lunit.TestCase("Bug-Report Tests") + +function bug:setup() + self.db = assert( sqlite3.open_memory() ) +end + +function bug:teardown() + assert_table( self.db:close() ) +end + + +function bug:test_1() + self.db:exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)") + + local query = assert_table( self.db:prepare("SELECT id FROM test WHERE value=?") ) + + assert_table ( query:bind("1") ) + assert_nil ( query:first_cols() ) + assert_table ( query:bind("2") ) + assert_nil ( query:first_cols() ) +end + + +function bug:test_nils() -- appeared in lua-5.1 (holes in arrays) + local function check(arg1, arg2, arg3, arg4, arg5) + assert_equal(1, arg1) + assert_equal(2, arg2) + assert_nil(arg3) + assert_equal(4, arg4) + assert_nil(arg5) + end + + self.db:set_function("test_nils", 5, function(arg1, arg2, arg3, arg4, arg5) + check(arg1, arg2, arg3, arg4, arg5) + end) + + assert_table( self.db:exec([[ SELECT test_nils(1, 2, NULL, 4, NULL) ]]) ) + + local arg1, arg2, arg3, arg4, arg5 = self.db:first_cols([[ SELECT 1, 2, NULL, 4, NULL ]]) + check(arg1, arg2, arg3, arg4, arg5) + + local row = assert_table( self.db:first_irow([[ SELECT 1, 2, NULL, 4, NULL ]]) ) + check(row[1], row[2], row[3], row[4], row[5]) +end + diff --git a/lua-sqlite3-0.4.1/tests.lua b/lua-sqlite3-0.4.1/tests.lua new file mode 100644 index 0000000..e4695ae --- /dev/null +++ b/lua-sqlite3-0.4.1/tests.lua @@ -0,0 +1,36 @@ + +--[[-------------------------------------------------------------------------- + + Author: Michael Roth + + Copyright (c) 2004 Michael Roth + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--]]-------------------------------------------------------------------------- + + +require "lunit" + +require "tests-sqlite3" +require "tests-luasql" + +lunit.run() + diff --git a/lua/.AppleDouble/.Parent b/lua/.AppleDouble/.Parent new file mode 100644 index 0000000..b338e15 Binary files /dev/null and b/lua/.AppleDouble/.Parent differ diff --git a/lua/.AppleDouble/script_device_demo.lua b/lua/.AppleDouble/script_device_demo.lua new file mode 100644 index 0000000..d54e93a Binary files /dev/null and b/lua/.AppleDouble/script_device_demo.lua differ diff --git a/lua/.AppleDouble/script_time_demo.lua b/lua/.AppleDouble/script_time_demo.lua new file mode 100644 index 0000000..de35994 Binary files /dev/null and b/lua/.AppleDouble/script_time_demo.lua differ diff --git a/lua/Archives/script_time_Camera.old b/lua/Archives/script_time_Camera.old new file mode 100755 index 0000000..2afd3bf --- /dev/null +++ b/lua/Archives/script_time_Camera.old @@ -0,0 +1,20 @@ +commandArray = {} + +--recupere les minutes +time=os.time() +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) + +pid=os.execute('cat /home/pi/motion/motion.pid') + +print("Motion pid= "..switch) +------------------------------------------------------------------------ + +if (pid == 0) then + commandArray['Camera1']='Off' +else + commandArray['Camera1']='On' +end + + +return commandArray diff --git a/lua/Archives/script_time_Camera2.lua b/lua/Archives/script_time_Camera2.lua new file mode 100755 index 0000000..b8bd790 --- /dev/null +++ b/lua/Archives/script_time_Camera2.lua @@ -0,0 +1,19 @@ +require "scripts/lua/functions" + +commandArray = {} + + +--recupere les minutes +time=os.time() +minutes=tonumber(os.date('%M',time)) + +if (minutes % 1 == 0) then + local f = io.popen("ls /media/WDBlue/motion/ |grep jpg| cut -c 1-2 |uniq| wc -l") -- runs command + local l = f:read("*a") -- read output of command + debug("Nombre de detection "..l) + f:close() + commandArray['PhotoMotion']=tostring(l) + commandArray['UpdateDevice']="1065|"..l +end + +return commandArray diff --git a/lua/Archives/script_time_Camera2.old b/lua/Archives/script_time_Camera2.old new file mode 100755 index 0000000..3ea4e54 --- /dev/null +++ b/lua/Archives/script_time_Camera2.old @@ -0,0 +1,19 @@ +require "scripts/lua/functions" + +commandArray = {} + + +--recupere les minutes +time=os.time() +minutes=tonumber(os.date('%M',time)) + +if (minutes % 10 == 0) then + local f = io.popen("ls /media/WDBlue/motion/ |grep jpg| cut -c 1-2 |uniq| wc -l") -- runs command + local l = f:read("*a") -- read output of command + debug("Nombre de detection "..l) + f:close() + commandArray['PhotoMotion']=tostring(l) + commandArray['UpdateDevice']="1065|"..l +end + +return commandArray diff --git a/lua/Archives/script_time_PC.old b/lua/Archives/script_time_PC.old new file mode 100755 index 0000000..fc47838 --- /dev/null +++ b/lua/Archives/script_time_PC.old @@ -0,0 +1,36 @@ +--Permet toutes les 15 minutes de renvoyer la commande actuelle sensée etre appliquée aux modules en 433 ( sans retour d'etat ) +require "scripts/lua/functions" + +commandArray = {} + +--recupere les minutes +time=os.time() +jour=tonumber(os.date('%w',time)) +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) + +-- --------------------------------------------------------------------------------------------------------- +-- Toutes les 30 minutes suffisent +-- --------------------------------------------------------------------------------------------------------- +if (minutes == 0 or minutes == 30 ) then + if (otherdevices['Vacances'] == 'On') then + switchIfNeeded['SonoJasper'] = 'Off' + else + if (jour == 0 or jour == 6) then + if (heures >= 08 and heures <= 23) then + switchIfNeeded('SonoJasper', 'On') + else + switchIfNeeded('SonoJasper', 'Off') + end + else + if (heures >= 20 and heures <= 23) then + switchIfNeeded('SonoJasper', 'On') + else + switchIfNeeded('SonoJasper', 'Off') + end + end + end + debug('##### Lancement du check tele chambre '..otherdevices['SonoJasper'] ) +end + +return commandArray diff --git a/lua/Archives/script_time_Presence.old b/lua/Archives/script_time_Presence.old new file mode 100755 index 0000000..3902816 --- /dev/null +++ b/lua/Archives/script_time_Presence.old @@ -0,0 +1,33 @@ +require "scripts/lua/functions" + +--Permet toutes les 15 minutes de renvoyer la commande actuelle sensée etre appliquée aux modules en 433 ( sans retour d'etat ) + +commandArray = {} + +--recupere les minutes +time=os.time() +jour=tonumber(os.date('%w',time)) +--mois=tonumber(os.date('%M',time)) +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) + +if (minutes % 10 == 0) then + debug('####### Lancement du check Presence ' ..heures..'h'..minutes) + if (otherdevices['Vacances'] == 'On') then + switchIfNeeded('Presence','Off') + else + --commandArray['Presence']='Off' + ------------------------------------------------------------------------ + if (josdJourChome()) then + switchIfNeeded('Presence','On') + else + if (heures > 17 or otherdevices["Zone B"] == 'On') then + switchIfNeeded('Presence','On') + else + switchIfNeeded('Presence','Off') + end + end + end +end + +return commandArray diff --git a/lua/Archives/script_time_Radiateur.old b/lua/Archives/script_time_Radiateur.old new file mode 100755 index 0000000..5fe7575 --- /dev/null +++ b/lua/Archives/script_time_Radiateur.old @@ -0,0 +1,108 @@ +--Permet toutes les 15 minutes de renvoyer la commande actuelle sensée etre appliquée aux modules en 433 ( sans retour d'etat ) + +commandArray = {} + +--recupere les minutes +time=os.time() +jour=tonumber(os.date('%w',time)) +--mois=tonumber(os.date('%M',time)) +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) + +-- Retourne le jour de la semaine (lundi...dimanche) +josdGetJourSemaineTab={[0]="dimanche",[1]="lundi",[2]="mardi",[3]="mercredi",[4]="jeudi",[5]="vendredi",[6]="samedi"} +function josdGetJourSemaine() + return josdGetJourSemaineTab[tonumber(os.date("%w"))] +end + +-- Retourne le jour de Pâques au format epoch +-- annee : année (Integer) dont on désire connaître le jour de Pâques (ex : 2014) +-- La fonction n'effectue le calcul que si l'année a changée depuis son dernier appel +josdGetJourPaquesAnnee=0 -- Variable globale (année du dernier calcul) pour ne pas recalculer le jour de Pâques à chaque appel +josdGetJourPaquesEpochPaque=0 -- Variable globale (jour de Pâques au format epoch) pour ne pas recalculer le jour de Pâques à chaque appel +function josdGetJourPaques(annee) + if(josdGetJourPaquesAnnee~=annee or josdGetJourPaquesEpochPaque==0) then + local a=math.floor(annee/100) + local b=math.fmod(annee,100) + local c=math.floor((3*(a+25))/4) + local d=math.fmod((3*(a+25)),4) + local e=math.floor((8*(a+11))/25) + local f=math.fmod((5*a+b),19) + local g=math.fmod((19*f+c-e),30) + local h=math.floor((f+11*g)/319) + local j=math.floor((60*(5-d)+b)/4) + local k=math.fmod((60*(5-d)+b),4) + local m=math.fmod((2*j-k-g+h),7) + local n=math.floor((g-h+m+114)/31) + local p=math.fmod((g-h+m+114),31) + local jour=p+1 + local mois=n + josdGetJourPaquesAnnee=annee + josdGetJourPaquesEpochPaque=os.time{year=annee,month=mois,day=jour,hour=12,min=0} + end + return josdGetJourPaquesEpochPaque +end + + +-- Retourne true si le jour courant est un jour férié +-- Le calcul des jours férié n'est fait qu'un fois par an (ou si la Vera reboot) +josdJourFerieAnnee=0 -- Variable globale (année du dernier calcul) pour ne pas recalculer le tableau à chaque appel +josdJourFerieTab = {} -- Variable globale (tableau des jours fériés) pour ne pas recalculer le tableau à chaque appel +function josdJourFerie() + local today=os.date("%m-%d") + local annee=tonumber(os.date("%Y")) + if(annee~=josdJourFerieAnnee) then + josdJourFerieAnnee=annee + -- Dates fixes + josdJourFerieTab["01-01"] = true -- 1er janvier + josdJourFerieTab["05-01"] = true -- Fête du travail + josdJourFerieTab["05-08"] = true -- Victoire des alliés + josdJourFerieTab["07-14"] = true -- Fête nationale + josdJourFerieTab["08-15"] = true -- Assomption + josdJourFerieTab["11-01"] = true -- Toussaint + josdJourFerieTab["11-11"] = true -- Armistice + josdJourFerieTab["12-25"] = true -- Noël + -- Dates variables + local epochPaques=josdGetJourPaques(annee) + josdJourFerieTab[os.date("%m-%d",epochPaques)] = true -- Pâques + josdJourFerieTab[os.date("%m-%d",epochPaques+24*60*60)] = true -- Lundi de Pâques = Pâques + 1 jour + josdJourFerieTab[os.date("%m-%d",epochPaques+24*60*60*39)] = true -- Ascension = Pâques + 39 jours + josdJourFerieTab[os.date("%m-%d",epochPaques+24*60*60*49)] = true -- Pentecôte = Ascension + 49 jours + end + return josdJourFerieTab[today] -- (nldr : Both nil and false make a condition false) +end +-- Retourne true si le jour courant est un jour chômé (passé à la maison) +-- Le calcul effectif n'est fait qu'une fois par jour (ou si la Vera reboot) +josdJourChomeToday="NULL" -- Variable globale (date du dernier calcul) pour ne pas recalculer le résultat à chaque appel +josdJourChomeReturn=false -- Variable globale (résulat du dernier calcul) pour ne pas recalculer le résultat à chaque appel +function josdJourChome() + local today=os.date("%Y-%m-%d") + if(today~=josdJourChomeToday) then -- Faut-il refaire le calcul ? + local jour=josdGetJourSemaine() + josdJourChomeToday=today + josdJourChomeReturn=(jour=="samedi" or jour=="dimanche" or jour=="mercredi" or josdJourFerie()) + -- or josdJourVacances()) + end + return josdJourChomeReturn +end + + +print('!*!*!*!*!*!*!*!*!Lancement du check Radiateur Bureau ' ..heures..'h'..minutes) + + +if (minutes == 0 or minutes == 10 or minutes == 20 or minutes == 30 or minutes == 40 or minutes == 50) then +if (otherdevices['Vacances'] == 'On') then + commandArray['RadiateurBureau']='Off' + print ('CHECK Temperature: Vacances -> ' ..otherdevices_svalues['TemperatureBarometre']) +else + ------------------------------------------------------------------------ + print ('CHECK Temperature: Travail -> ' ..otherdevices_svalues['TemperatureBarometre']) + if (tonumber(otherdevices_svalues['TemperatureBarometre']) <= 17.0) then + commandArray['RadiateurBureau']='Off' + else + commandArray['RadiateurBureau']='On' + end +end +end + +return commandArray diff --git a/lua/Archives/script_time_hc.old b/lua/Archives/script_time_hc.old new file mode 100755 index 0000000..104d9e6 --- /dev/null +++ b/lua/Archives/script_time_hc.old @@ -0,0 +1,23 @@ +--Permet toutes les 15 minutes de renvoyer la commande actuelle sensée etre appliquée aux modules en 433 ( sans retour d'etat ) + require "scripts/lua/functions" + +commandArray = {} + +--recupere les minutes +time=os.time() +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) + + +------------------------------------------------------------------------ + +if (minutes == 0 or minutes == 30) then + print('######### Lancement du check Heures Creuses' ..heures..'h'..minutes) + if ((heures > 21 or (heures == 21 and minutes >= 30)) or (heures < 5 or (heures == 5 and minutes <= 30))) then + switchIfNeeded('HeuresCreuses', 'On') + else + switchIfNeeded('HeuresCreuses', 'Off') + end +end + +return commandArray diff --git a/lua/Archives/script_time_ping.old b/lua/Archives/script_time_ping.old new file mode 100755 index 0000000..6b29a12 --- /dev/null +++ b/lua/Archives/script_time_ping.old @@ -0,0 +1,17 @@ +commandArray = {} + +print("Debut pingVolumio2") +ping_success=os.execute('ping -c1 volumio') +if ping_success then + if ( otherdevices['Volumio2'] == 'Off') then + print("pingVolumio2 success") + commandArray['Volumio2']='On' + end +else + if (otherdevices['Volumio2'] == 'On') then + print("pingVolumio2 fail") + commandArray['Volumio2']='Off' + end +end +print("fin pingVolumio2") +return commandArray diff --git a/lua/Archives/script_time_ping2.old b/lua/Archives/script_time_ping2.old new file mode 100755 index 0000000..6cb4988 --- /dev/null +++ b/lua/Archives/script_time_ping2.old @@ -0,0 +1,78 @@ +--Initialise la commande de retour finale +commandArray={} + + +--Mode deboggage (affichage des messages) +debug=true +--Prefixe pour les sorties de log +prefixe="(PING) " + +--recupere les minutes +time=os.time() +minutes=tonumber(os.date('%M',time)) + +if (minutes == 0 or minutes == 10 or minutes == 20 or minutes == 30 or minutes == 40 or minutes == 50) then + +--Tableau des périphériques à "pinguer" +-- Key = adresse ip à pinguer +-- Value = périphérique virtuel à switcher +local ping={} +ping['volumio']='Volumio2' +ping['achille']='Achille' +ping['akhenaton']='Akhenaton' +ping['hackintosh']='Hackintosh' +ping['xbmc']='Xbmc' +ping['akhesa']='Akhesa' +ping['theo']='Theo' +ping['s3-mini']='Moi' +ping['manon']='Manon' +ping['domi1']='Domi1' +ping['domi2']='Domi2' +ping['soutihp']='ImprimanteHp' +ping['192.168.0.17']='Telechambre' +-- Pas de ping de la box ?? == Panne de courant +--ping['192.168.1.1']='PanneCourant' +--ping['192.168.0.20']='Presence Camera Interieure' +--ping['192.168.0.21']='Presence Camera Exterieure' +--ping['192.168.0.100']='Presence Raspberry' + +AuMoinsUnPing=false +--pour chaque entree du tableau +for ip, switch in pairs(ping) do + + --Le Ping ! : -c1 = Un seul ping , -w1 délai d'une seconde d'attente de réponse + ping_success=os.execute('ping -c1 -w1 '..ip) + + + --Si le ping à répondu + if ping_success then + AuMoinsUnPing=true + if(debug==true)then + print(prefixe.."ping success "..switch) + end + --si le switch etait sur off on l'allume + if(otherdevices[switch]=='Off') then + commandArray[switch]='On' + end + else + + --Si pas de réponse + if(debug==true)then + print(prefixe.."ping fail "..switch) + end + --si le switch etait sur oN on l'eteind + if(otherdevices[switch]=='On') then + commandArray[switch]='Off' + end + end +end + +if AuMoinsUnPing then + commandArray['PanneCourant']='Off' +else + commandArray['PanneCourant']='On' +end +end + +return commandArray + diff --git a/lua/JSON.lua b/lua/JSON.lua new file mode 100644 index 0000000..e1bcade --- /dev/null +++ b/lua/JSON.lua @@ -0,0 +1,1743 @@ +-- -*- coding: utf-8 -*- +-- +-- Simple JSON encoding and decoding in pure Lua. +-- +-- Copyright 2010-2017 Jeffrey Friedl +-- http://regex.info/blog/ +-- Latest version: http://regex.info/blog/lua/json +-- +-- This code is released under a Creative Commons CC-BY "Attribution" License: +-- http://creativecommons.org/licenses/by/3.0/deed.en_US +-- +-- It can be used for any purpose so long as: +-- 1) the copyright notice above is maintained +-- 2) the web-page links above are maintained +-- 3) the 'AUTHOR_NOTE' string below is maintained +-- +local VERSION = '20170927.26' -- version history at end of file +local AUTHOR_NOTE = "-[ JSON.lua package by Jeffrey Friedl (http://regex.info/blog/lua/json) version 20170927.26 ]-" + +-- +-- The 'AUTHOR_NOTE' variable exists so that information about the source +-- of the package is maintained even in compiled versions. It's also +-- included in OBJDEF below mostly to quiet warnings about unused variables. +-- +local OBJDEF = { + VERSION = VERSION, + AUTHOR_NOTE = AUTHOR_NOTE, +} + +-- +-- Simple JSON encoding and decoding in pure Lua. +-- JSON definition: http://www.json.org/ +-- +-- +-- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines +-- +-- local lua_value = JSON:decode(raw_json_text) +-- +-- local raw_json_text = JSON:encode(lua_table_or_value) +-- local pretty_json_text = JSON:encode_pretty(lua_table_or_value) -- "pretty printed" version for human readability +-- +-- +-- +-- DECODING (from a JSON string to a Lua table) +-- +-- +-- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines +-- +-- local lua_value = JSON:decode(raw_json_text) +-- +-- If the JSON text is for an object or an array, e.g. +-- { "what": "books", "count": 3 } +-- or +-- [ "Larry", "Curly", "Moe" ] +-- +-- the result is a Lua table, e.g. +-- { what = "books", count = 3 } +-- or +-- { "Larry", "Curly", "Moe" } +-- +-- +-- The encode and decode routines accept an optional second argument, +-- "etc", which is not used during encoding or decoding, but upon error +-- is passed along to error handlers. It can be of any type (including nil). +-- +-- +-- +-- ERROR HANDLING DURING DECODE +-- +-- With most errors during decoding, this code calls +-- +-- JSON:onDecodeError(message, text, location, etc) +-- +-- with a message about the error, and if known, the JSON text being +-- parsed and the byte count where the problem was discovered. You can +-- replace the default JSON:onDecodeError() with your own function. +-- +-- The default onDecodeError() merely augments the message with data +-- about the text and the location (and, an 'etc' argument had been +-- provided to decode(), its value is tacked onto the message as well), +-- and then calls JSON.assert(), which itself defaults to Lua's built-in +-- assert(), and can also be overridden. +-- +-- For example, in an Adobe Lightroom plugin, you might use something like +-- +-- function JSON:onDecodeError(message, text, location, etc) +-- LrErrors.throwUserError("Internal Error: invalid JSON data") +-- end +-- +-- or even just +-- +-- function JSON.assert(message) +-- LrErrors.throwUserError("Internal Error: " .. message) +-- end +-- +-- If JSON:decode() is passed a nil, this is called instead: +-- +-- JSON:onDecodeOfNilError(message, nil, nil, etc) +-- +-- and if JSON:decode() is passed HTML instead of JSON, this is called: +-- +-- JSON:onDecodeOfHTMLError(message, text, nil, etc) +-- +-- The use of the 'etc' argument allows stronger coordination between +-- decoding and error reporting, especially when you provide your own +-- error-handling routines. Continuing with the the Adobe Lightroom +-- plugin example: +-- +-- function JSON:onDecodeError(message, text, location, etc) +-- local note = "Internal Error: invalid JSON data" +-- if type(etc) = 'table' and etc.photo then +-- note = note .. " while processing for " .. etc.photo:getFormattedMetadata('fileName') +-- end +-- LrErrors.throwUserError(note) +-- end +-- +-- : +-- : +-- +-- for i, photo in ipairs(photosToProcess) do +-- : +-- : +-- local data = JSON:decode(someJsonText, { photo = photo }) +-- : +-- : +-- end +-- +-- +-- +-- If the JSON text passed to decode() has trailing garbage (e.g. as with the JSON "[123]xyzzy"), +-- the method +-- +-- JSON:onTrailingGarbage(json_text, location, parsed_value, etc) +-- +-- is invoked, where: +-- +-- 'json_text' is the original JSON text being parsed, +-- 'location' is the count of bytes into 'json_text' where the garbage starts (6 in the example), +-- 'parsed_value' is the Lua result of what was successfully parsed ({123} in the example), +-- 'etc' is as above. +-- +-- If JSON:onTrailingGarbage() does not abort, it should return the value decode() should return, +-- or nil + an error message. +-- +-- local new_value, error_message = JSON:onTrailingGarbage() +-- +-- The default JSON:onTrailingGarbage() simply invokes JSON:onDecodeError("trailing garbage"...), +-- but you can have this package ignore trailing garbage via +-- +-- function JSON:onTrailingGarbage(json_text, location, parsed_value, etc) +-- return parsed_value +-- end +-- +-- +-- DECODING AND STRICT TYPES +-- +-- Because both JSON objects and JSON arrays are converted to Lua tables, +-- it's not normally possible to tell which original JSON type a +-- particular Lua table was derived from, or guarantee decode-encode +-- round-trip equivalency. +-- +-- However, if you enable strictTypes, e.g. +-- +-- JSON = assert(loadfile "JSON.lua")() --load the routines +-- JSON.strictTypes = true +-- +-- then the Lua table resulting from the decoding of a JSON object or +-- JSON array is marked via Lua metatable, so that when re-encoded with +-- JSON:encode() it ends up as the appropriate JSON type. +-- +-- (This is not the default because other routines may not work well with +-- tables that have a metatable set, for example, Lightroom API calls.) +-- +-- +-- ENCODING (from a lua table to a JSON string) +-- +-- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines +-- +-- local raw_json_text = JSON:encode(lua_table_or_value) +-- local pretty_json_text = JSON:encode_pretty(lua_table_or_value) -- "pretty printed" version for human readability +-- local custom_pretty = JSON:encode(lua_table_or_value, etc, { pretty = true, indent = "| ", align_keys = false }) +-- +-- On error during encoding, this code calls: +-- +-- JSON:onEncodeError(message, etc) +-- +-- which you can override in your local JSON object. Also see "HANDLING UNSUPPORTED VALUE TYPES" below. +-- +-- The 'etc' in the error call is the second argument to encode() and encode_pretty(), or nil if it wasn't provided. +-- +-- +-- +-- +-- ENCODING OPTIONS +-- +-- An optional third argument, a table of options, can be provided to encode(). +-- +-- encode_options = { +-- -- options for making "pretty" human-readable JSON (see "PRETTY-PRINTING" below) +-- pretty = true, -- turn pretty formatting on +-- indent = " ", -- use this indent for each level of an array/object +-- align_keys = false, -- if true, align the keys in a way that sounds like it should be nice, but is actually ugly +-- array_newline = false, -- if true, array elements become one to a line rather than inline +-- +-- -- other output-related options +-- null = "\0", -- see "ENCODING JSON NULL VALUES" below +-- stringsAreUtf8 = false, -- see "HANDLING UNICODE LINE AND PARAGRAPH SEPARATORS FOR JAVA" below +-- } +-- +-- json_string = JSON:encode(mytable, etc, encode_options) +-- +-- +-- +-- For reference, the defaults are: +-- +-- pretty = false +-- null = nil, +-- stringsAreUtf8 = false, +-- +-- +-- +-- PRETTY-PRINTING +-- +-- Enabling the 'pretty' encode option helps generate human-readable JSON. +-- +-- pretty = JSON:encode(val, etc, { +-- pretty = true, +-- indent = " ", +-- align_keys = false, +-- }) +-- +-- encode_pretty() is also provided: it's identical to encode() except +-- that encode_pretty() provides a default options table if none given in the call: +-- +-- { pretty = true, indent = " ", align_keys = false, array_newline = false } +-- +-- For example, if +-- +-- JSON:encode(data) +-- +-- produces: +-- +-- {"city":"Kyoto","climate":{"avg_temp":16,"humidity":"high","snowfall":"minimal"},"country":"Japan","wards":11} +-- +-- then +-- +-- JSON:encode_pretty(data) +-- +-- produces: +-- +-- { +-- "city": "Kyoto", +-- "climate": { +-- "avg_temp": 16, +-- "humidity": "high", +-- "snowfall": "minimal" +-- }, +-- "country": "Japan", +-- "wards": 11 +-- } +-- +-- The following lines all return identical strings: +-- JSON:encode_pretty(data) +-- JSON:encode_pretty(data, nil, { pretty = true, indent = " ", align_keys = false, array_newline = false}) +-- JSON:encode_pretty(data, nil, { pretty = true, indent = " " }) +-- JSON:encode (data, nil, { pretty = true, indent = " " }) +-- +-- An example of setting your own indent string: +-- +-- JSON:encode_pretty(data, nil, { pretty = true, indent = "| " }) +-- +-- produces: +-- +-- { +-- | "city": "Kyoto", +-- | "climate": { +-- | | "avg_temp": 16, +-- | | "humidity": "high", +-- | | "snowfall": "minimal" +-- | }, +-- | "country": "Japan", +-- | "wards": 11 +-- } +-- +-- An example of setting align_keys to true: +-- +-- JSON:encode_pretty(data, nil, { pretty = true, indent = " ", align_keys = true }) +-- +-- produces: +-- +-- { +-- "city": "Kyoto", +-- "climate": { +-- "avg_temp": 16, +-- "humidity": "high", +-- "snowfall": "minimal" +-- }, +-- "country": "Japan", +-- "wards": 11 +-- } +-- +-- which I must admit is kinda ugly, sorry. This was the default for +-- encode_pretty() prior to version 20141223.14. +-- +-- +-- HANDLING UNICODE LINE AND PARAGRAPH SEPARATORS FOR JAVA +-- +-- If the 'stringsAreUtf8' encode option is set to true, consider Lua strings not as a sequence of bytes, +-- but as a sequence of UTF-8 characters. +-- +-- Currently, the only practical effect of setting this option is that Unicode LINE and PARAGRAPH +-- separators, if found in a string, are encoded with a JSON escape instead of being dumped as is. +-- The JSON is valid either way, but encoding this way, apparently, allows the resulting JSON +-- to also be valid Java. +-- +-- AMBIGUOUS SITUATIONS DURING THE ENCODING +-- +-- During the encode, if a Lua table being encoded contains both string +-- and numeric keys, it fits neither JSON's idea of an object, nor its +-- idea of an array. To get around this, when any string key exists (or +-- when non-positive numeric keys exist), numeric keys are converted to +-- strings. +-- +-- For example, +-- JSON:encode({ "one", "two", "three", SOMESTRING = "some string" })) +-- produces the JSON object +-- {"1":"one","2":"two","3":"three","SOMESTRING":"some string"} +-- +-- To prohibit this conversion and instead make it an error condition, set +-- JSON.noKeyConversion = true +-- +-- +-- ENCODING JSON NULL VALUES +-- +-- Lua tables completely omit keys whose value is nil, so without special handling there's +-- no way to represent JSON object's null value in a Lua table. For example +-- JSON:encode({ username = "admin", password = nil }) +-- +-- produces: +-- +-- {"username":"admin"} +-- +-- In order to actually produce +-- +-- {"username":"admin", "password":null} +-- + +-- one can include a string value for a "null" field in the options table passed to encode().... +-- any Lua table entry with that value becomes null in the JSON output: +-- +-- JSON:encode({ username = "admin", password = "xyzzy" }, -- First arg is the Lua table to encode as JSON. +-- nil, -- Second arg is the 'etc' value, ignored here +-- { null = "xyzzy" }) -- Third arg is th options table +-- +-- produces: +-- +-- {"username":"admin", "password":null} +-- +-- Just be sure to use a string that is otherwise unlikely to appear in your data. +-- The string "\0" (a string with one null byte) may well be appropriate for many applications. +-- +-- The "null" options also applies to Lua tables that become JSON arrays. +-- JSON:encode({ "one", "two", nil, nil }) +-- +-- produces +-- +-- ["one","two"] +-- +-- while +-- +-- NullPlaceholder = "\0" +-- encode_options = { null = NullPlaceholder } +-- JSON:encode({ "one", "two", NullPlaceholder, NullPlaceholder}, nil, encode_options) +-- produces +-- +-- ["one","two",null,null] +-- +-- +-- +-- HANDLING LARGE AND/OR PRECISE NUMBERS +-- +-- +-- Without special handling, numbers in JSON can lose precision in Lua. +-- For example: +-- +-- T = JSON:decode('{ "small":12345, "big":12345678901234567890123456789, "precise":9876.67890123456789012345 }') +-- +-- print("small: ", type(T.small), T.small) +-- print("big: ", type(T.big), T.big) +-- print("precise: ", type(T.precise), T.precise) +-- +-- produces +-- +-- small: number 12345 +-- big: number 1.2345678901235e+28 +-- precise: number 9876.6789012346 +-- +-- Precision is lost with both 'big' and 'precise'. +-- +-- This package offers ways to try to handle this better (for some definitions of "better")... +-- +-- The most precise method is by setting the global: +-- +-- JSON.decodeNumbersAsObjects = true +-- +-- When this is set, numeric JSON data is encoded into Lua in a form that preserves the exact +-- JSON numeric presentation when re-encoded back out to JSON, or accessed in Lua as a string. +-- +-- This is done by encoding the numeric data with a Lua table/metatable that returns +-- the possibly-imprecise numeric form when accessed numerically, but the original precise +-- representation when accessed as a string. +-- +-- Consider the example above, with this option turned on: +-- +-- JSON.decodeNumbersAsObjects = true +-- +-- T = JSON:decode('{ "small":12345, "big":12345678901234567890123456789, "precise":9876.67890123456789012345 }') +-- +-- print("small: ", type(T.small), T.small) +-- print("big: ", type(T.big), T.big) +-- print("precise: ", type(T.precise), T.precise) +-- +-- This now produces: +-- +-- small: table 12345 +-- big: table 12345678901234567890123456789 +-- precise: table 9876.67890123456789012345 +-- +-- However, within Lua you can still use the values (e.g. T.precise in the example above) in numeric +-- contexts. In such cases you'll get the possibly-imprecise numeric version, but in string contexts +-- and when the data finds its way to this package's encode() function, the original full-precision +-- representation is used. +-- +-- You can force access to the string or numeric version via +-- JSON:forceString() +-- JSON:forceNumber() +-- For example, +-- local probably_okay = JSON:forceNumber(T.small) -- 'probably_okay' is a number +-- +-- Code the inspects the JSON-turned-Lua data using type() can run into troubles because what used to +-- be a number can now be a table (e.g. as the small/big/precise example above shows). Update these +-- situations to use JSON:isNumber(item), which returns nil if the item is neither a number nor one +-- of these number objects. If it is either, it returns the number itself. For completeness there's +-- also JSON:isString(item). +-- +-- If you want to try to avoid the hassles of this "number as an object" kludge for all but really +-- big numbers, you can set JSON.decodeNumbersAsObjects and then also set one or both of +-- JSON:decodeIntegerObjectificationLength +-- JSON:decodeDecimalObjectificationLength +-- They refer to the length of the part of the number before and after a decimal point. If they are +-- set and their part is at least that number of digits, objectification occurs. If both are set, +-- objectification occurs when either length is met. +-- +-- ----------------------- +-- +-- Even without using the JSON.decodeNumbersAsObjects option, you can encode numbers in your Lua +-- table that retain high precision upon encoding to JSON, by using the JSON:asNumber() function: +-- +-- T = { +-- imprecise = 123456789123456789.123456789123456789, +-- precise = JSON:asNumber("123456789123456789.123456789123456789") +-- } +-- +-- print(JSON:encode_pretty(T)) +-- +-- This produces: +-- +-- { +-- "precise": 123456789123456789.123456789123456789, +-- "imprecise": 1.2345678912346e+17 +-- } +-- +-- +-- ----------------------- +-- +-- A different way to handle big/precise JSON numbers is to have decode() merely return the exact +-- string representation of the number instead of the number itself. This approach might be useful +-- when the numbers are merely some kind of opaque object identifier and you want to work with them +-- in Lua as strings anyway. +-- +-- This approach is enabled by setting +-- +-- JSON.decodeIntegerStringificationLength = 10 +-- +-- The value is the number of digits (of the integer part of the number) at which to stringify numbers. +-- NOTE: this setting is ignored if JSON.decodeNumbersAsObjects is true, as that takes precedence. +-- +-- Consider our previous example with this option set to 10: +-- +-- JSON.decodeIntegerStringificationLength = 10 +-- +-- T = JSON:decode('{ "small":12345, "big":12345678901234567890123456789, "precise":9876.67890123456789012345 }') +-- +-- print("small: ", type(T.small), T.small) +-- print("big: ", type(T.big), T.big) +-- print("precise: ", type(T.precise), T.precise) +-- +-- This produces: +-- +-- small: number 12345 +-- big: string 12345678901234567890123456789 +-- precise: number 9876.6789012346 +-- +-- The long integer of the 'big' field is at least JSON.decodeIntegerStringificationLength digits +-- in length, so it's converted not to a Lua integer but to a Lua string. Using a value of 0 or 1 ensures +-- that all JSON numeric data becomes strings in Lua. +-- +-- Note that unlike +-- JSON.decodeNumbersAsObjects = true +-- this stringification is simple and unintelligent: the JSON number simply becomes a Lua string, and that's the end of it. +-- If the string is then converted back to JSON, it's still a string. After running the code above, adding +-- print(JSON:encode(T)) +-- produces +-- {"big":"12345678901234567890123456789","precise":9876.6789012346,"small":12345} +-- which is unlikely to be desired. +-- +-- There's a comparable option for the length of the decimal part of a number: +-- +-- JSON.decodeDecimalStringificationLength +-- +-- This can be used alone or in conjunction with +-- +-- JSON.decodeIntegerStringificationLength +-- +-- to trip stringification on precise numbers with at least JSON.decodeIntegerStringificationLength digits after +-- the decimal point. (Both are ignored if JSON.decodeNumbersAsObjects is true.) +-- +-- This example: +-- +-- JSON.decodeIntegerStringificationLength = 10 +-- JSON.decodeDecimalStringificationLength = 5 +-- +-- T = JSON:decode('{ "small":12345, "big":12345678901234567890123456789, "precise":9876.67890123456789012345 }') +-- +-- print("small: ", type(T.small), T.small) +-- print("big: ", type(T.big), T.big) +-- print("precise: ", type(T.precise), T.precise) +-- +-- produces: +-- +-- small: number 12345 +-- big: string 12345678901234567890123456789 +-- precise: string 9876.67890123456789012345 +-- +-- +-- HANDLING UNSUPPORTED VALUE TYPES +-- +-- Among the encoding errors that might be raised is an attempt to convert a table value that has a type +-- that this package hasn't accounted for: a function, userdata, or a thread. You can handle these types as table +-- values (but not as table keys) if you supply a JSON:unsupportedTypeEncoder() method along the lines of the +-- following example: +-- +-- function JSON:unsupportedTypeEncoder(value_of_unsupported_type) +-- if type(value_of_unsupported_type) == 'function' then +-- return "a function value" +-- else +-- return nil +-- end +-- end +-- +-- Your unsupportedTypeEncoder() method is actually called with a bunch of arguments: +-- +-- self:unsupportedTypeEncoder(value, parents, etc, options, indent, for_key) +-- +-- The 'value' is the function, thread, or userdata to be converted to JSON. +-- +-- The 'etc' and 'options' arguments are those passed to the original encode(). The other arguments are +-- probably of little interest; see the source code. (Note that 'for_key' is never true, as this function +-- is invoked only on table values; table keys of these types still trigger the onEncodeError method.) +-- +-- If your unsupportedTypeEncoder() method returns a string, it's inserted into the JSON as is. +-- If it returns nil plus an error message, that error message is passed through to an onEncodeError invocation. +-- If it returns only nil, processing falls through to a default onEncodeError invocation. +-- +-- If you want to handle everything in a simple way: +-- +-- function JSON:unsupportedTypeEncoder(value) +-- return tostring(value) +-- end +-- +-- +-- SUMMARY OF METHODS YOU CAN OVERRIDE IN YOUR LOCAL LUA JSON OBJECT +-- +-- assert +-- onDecodeError +-- onDecodeOfNilError +-- onDecodeOfHTMLError +-- onTrailingGarbage +-- onEncodeError +-- unsupportedTypeEncoder +-- +-- If you want to create a separate Lua JSON object with its own error handlers, +-- you can reload JSON.lua or use the :new() method. +-- +--------------------------------------------------------------------------- + +local default_pretty_indent = " " +local default_pretty_options = { pretty = true, indent = default_pretty_indent, align_keys = false, array_newline = false } + +local isArray = { __tostring = function() + return "JSON array" +end } +isArray.__index = isArray +local isObject = { __tostring = function() + return "JSON object" +end } +isObject.__index = isObject + +function OBJDEF:newArray(tbl) + return setmetatable(tbl or {}, isArray) +end + +function OBJDEF:newObject(tbl) + return setmetatable(tbl or {}, isObject) +end + +local function getnum(op) + return type(op) == 'number' and op or op.N +end + +local isNumber = { + __tostring = function(T) + return T.S + end, + __unm = function(op) + return getnum(op) + end, + + __concat = function(op1, op2) + return tostring(op1) .. tostring(op2) + end, + __add = function(op1, op2) + return getnum(op1) + getnum(op2) + end, + __sub = function(op1, op2) + return getnum(op1) - getnum(op2) + end, + __mul = function(op1, op2) + return getnum(op1) * getnum(op2) + end, + __div = function(op1, op2) + return getnum(op1) / getnum(op2) + end, + __mod = function(op1, op2) + return getnum(op1) % getnum(op2) + end, + __pow = function(op1, op2) + return getnum(op1) ^ getnum(op2) + end, + __lt = function(op1, op2) + return getnum(op1) < getnum(op2) + end, + __eq = function(op1, op2) + return getnum(op1) == getnum(op2) + end, + __le = function(op1, op2) + return getnum(op1) <= getnum(op2) + end, +} +isNumber.__index = isNumber + +function OBJDEF:asNumber(item) + + if getmetatable(item) == isNumber then + -- it's already a JSON number object. + return item + elseif type(item) == 'table' and type(item.S) == 'string' and type(item.N) == 'number' then + -- it's a number-object table that lost its metatable, so give it one + return setmetatable(item, isNumber) + else + -- the normal situation... given a number or a string representation of a number.... + local holder = { + S = tostring(item), -- S is the representation of the number as a string, which remains precise + N = tonumber(item), -- N is the number as a Lua number. + } + return setmetatable(holder, isNumber) + end +end + +-- +-- Given an item that might be a normal string or number, or might be an 'isNumber' object defined above, +-- return the string version. This shouldn't be needed often because the 'isNumber' object should autoconvert +-- to a string in most cases, but it's here to allow it to be forced when needed. +-- +function OBJDEF:forceString(item) + if type(item) == 'table' and type(item.S) == 'string' then + return item.S + else + return tostring(item) + end +end + +-- +-- Given an item that might be a normal string or number, or might be an 'isNumber' object defined above, +-- return the numeric version. +-- +function OBJDEF:forceNumber(item) + if type(item) == 'table' and type(item.N) == 'number' then + return item.N + else + return tonumber(item) + end +end + +-- +-- If the given item is a number, return it. Otherwise, return nil. +-- This, this can be used both in a conditional and to access the number when you're not sure its form. +-- +function OBJDEF:isNumber(item) + if type(item) == 'number' then + return item + elseif type(item) == 'table' and type(item.N) == 'number' then + return item.N + else + return nil + end +end + +function OBJDEF:isString(item) + if type(item) == 'string' then + return item + elseif type(item) == 'table' and type(item.S) == 'string' then + return item.S + else + return nil + end +end + +local function unicode_codepoint_as_utf8(codepoint) + -- + -- codepoint is a number + -- + if codepoint <= 127 then + return string.char(codepoint) + + elseif codepoint <= 2047 then + -- + -- 110yyyxx 10xxxxxx <-- useful notation from http://en.wikipedia.org/wiki/Utf8 + -- + local highpart = math.floor(codepoint / 0x40) + local lowpart = codepoint - (0x40 * highpart) + return string.char(0xC0 + highpart, + 0x80 + lowpart) + + elseif codepoint <= 65535 then + -- + -- 1110yyyy 10yyyyxx 10xxxxxx + -- + local highpart = math.floor(codepoint / 0x1000) + local remainder = codepoint - 0x1000 * highpart + local midpart = math.floor(remainder / 0x40) + local lowpart = remainder - 0x40 * midpart + + highpart = 0xE0 + highpart + midpart = 0x80 + midpart + lowpart = 0x80 + lowpart + + -- + -- Check for an invalid character (thanks Andy R. at Adobe). + -- See table 3.7, page 93, in http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf#G28070 + -- + if (highpart == 0xE0 and midpart < 0xA0) or + (highpart == 0xED and midpart > 0x9F) or + (highpart == 0xF0 and midpart < 0x90) or + (highpart == 0xF4 and midpart > 0x8F) + then + return "?" + else + return string.char(highpart, + midpart, + lowpart) + end + + else + -- + -- 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx + -- + local highpart = math.floor(codepoint / 0x40000) + local remainder = codepoint - 0x40000 * highpart + local midA = math.floor(remainder / 0x1000) + remainder = remainder - 0x1000 * midA + local midB = math.floor(remainder / 0x40) + local lowpart = remainder - 0x40 * midB + + return string.char(0xF0 + highpart, + 0x80 + midA, + 0x80 + midB, + 0x80 + lowpart) + end +end + +function OBJDEF:onDecodeError(message, text, location, etc) + if text then + if location then + message = string.format("%s at byte %d of: %s", message, location, text) + else + message = string.format("%s: %s", message, text) + end + end + + if etc ~= nil then + message = message .. " (" .. OBJDEF:encode(etc) .. ")" + end + + if self.assert then + self.assert(false, message) + else + assert(false, message) + end +end + +function OBJDEF:onTrailingGarbage(json_text, location, parsed_value, etc) + return self:onDecodeError("trailing garbage", json_text, location, etc) +end + +OBJDEF.onDecodeOfNilError = OBJDEF.onDecodeError +OBJDEF.onDecodeOfHTMLError = OBJDEF.onDecodeError + +function OBJDEF:onEncodeError(message, etc) + if etc ~= nil then + message = message .. " (" .. OBJDEF:encode(etc) .. ")" + end + + if self.assert then + self.assert(false, message) + else + assert(false, message) + end +end + +local function grok_number(self, text, start, options) + -- + -- Grab the integer part + -- + local integer_part = text:match('^-?[1-9]%d*', start) + or text:match("^-?0", start) + + if not integer_part then + self:onDecodeError("expected number", text, start, options.etc) + return nil, start -- in case the error method doesn't abort, return something sensible + end + + local i = start + integer_part:len() + + -- + -- Grab an optional decimal part + -- + local decimal_part = text:match('^%.%d+', i) or "" + + i = i + decimal_part:len() + + -- + -- Grab an optional exponential part + -- + local exponent_part = text:match('^[eE][-+]?%d+', i) or "" + + i = i + exponent_part:len() + + local full_number_text = integer_part .. decimal_part .. exponent_part + + if options.decodeNumbersAsObjects then + + local objectify = false + + if not options.decodeIntegerObjectificationLength and not options.decodeDecimalObjectificationLength then + -- no options, so objectify + objectify = true + + elseif (options.decodeIntegerObjectificationLength + and + (integer_part:len() >= options.decodeIntegerObjectificationLength or exponent_part:len() > 0)) + + or + (options.decodeDecimalObjectificationLength + and + (decimal_part:len() >= options.decodeDecimalObjectificationLength or exponent_part:len() > 0)) + then + -- have options and they are triggered, so objectify + objectify = true + end + + if objectify then + return OBJDEF:asNumber(full_number_text), i + end + -- else, fall through to try to return as a straight-up number + + else + + -- Not always decoding numbers as objects, so perhaps encode as strings? + + -- + -- If we're told to stringify only under certain conditions, so do. + -- We punt a bit when there's an exponent by just stringifying no matter what. + -- I suppose we should really look to see whether the exponent is actually big enough one + -- way or the other to trip stringification, but I'll be lazy about it until someone asks. + -- + if (options.decodeIntegerStringificationLength + and + (integer_part:len() >= options.decodeIntegerStringificationLength or exponent_part:len() > 0)) + + or + + (options.decodeDecimalStringificationLength + and + (decimal_part:len() >= options.decodeDecimalStringificationLength or exponent_part:len() > 0)) + then + return full_number_text, i -- this returns the exact string representation seen in the original JSON + end + + end + + local as_number = tonumber(full_number_text) + + if not as_number then + self:onDecodeError("bad number", text, start, options.etc) + return nil, start -- in case the error method doesn't abort, return something sensible + end + + return as_number, i +end + +local function grok_string(self, text, start, options) + + if text:sub(start, start) ~= '"' then + self:onDecodeError("expected string's opening quote", text, start, options.etc) + return nil, start -- in case the error method doesn't abort, return something sensible + end + + local i = start + 1 -- +1 to bypass the initial quote + local text_len = text:len() + local VALUE = "" + while i <= text_len do + local c = text:sub(i, i) + if c == '"' then + return VALUE, i + 1 + end + if c ~= '\\' then + VALUE = VALUE .. c + i = i + 1 + elseif text:match('^\\b', i) then + VALUE = VALUE .. "\b" + i = i + 2 + elseif text:match('^\\f', i) then + VALUE = VALUE .. "\f" + i = i + 2 + elseif text:match('^\\n', i) then + VALUE = VALUE .. "\n" + i = i + 2 + elseif text:match('^\\r', i) then + VALUE = VALUE .. "\r" + i = i + 2 + elseif text:match('^\\t', i) then + VALUE = VALUE .. "\t" + i = i + 2 + else + local hex = text:match('^\\u([0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF])', i) + if hex then + i = i + 6 -- bypass what we just read + + -- We have a Unicode codepoint. It could be standalone, or if in the proper range and + -- followed by another in a specific range, it'll be a two-code surrogate pair. + local codepoint = tonumber(hex, 16) + if codepoint >= 0xD800 and codepoint <= 0xDBFF then + -- it's a hi surrogate... see whether we have a following low + local lo_surrogate = text:match('^\\u([dD][cdefCDEF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF])', i) + if lo_surrogate then + i = i + 6 -- bypass the low surrogate we just read + codepoint = 0x2400 + (codepoint - 0xD800) * 0x400 + tonumber(lo_surrogate, 16) + else + -- not a proper low, so we'll just leave the first codepoint as is and spit it out. + end + end + VALUE = VALUE .. unicode_codepoint_as_utf8(codepoint) + + else + + -- just pass through what's escaped + VALUE = VALUE .. text:match('^\\(.)', i) + i = i + 2 + end + end + end + + self:onDecodeError("unclosed string", text, start, options.etc) + return nil, start -- in case the error method doesn't abort, return something sensible +end + +local function skip_whitespace(text, start) + + local _, match_end = text:find("^[ \n\r\t]+", start) -- [http://www.ietf.org/rfc/rfc4627.txt] Section 2 + if match_end then + return match_end + 1 + else + return start + end +end + +local grok_one -- assigned later + +local function grok_object(self, text, start, options) + + if text:sub(start, start) ~= '{' then + self:onDecodeError("expected '{'", text, start, options.etc) + return nil, start -- in case the error method doesn't abort, return something sensible + end + + local i = skip_whitespace(text, start + 1) -- +1 to skip the '{' + + local VALUE = self.strictTypes and self:newObject { } or { } + + if text:sub(i, i) == '}' then + return VALUE, i + 1 + end + local text_len = text:len() + while i <= text_len do + local key, new_i = grok_string(self, text, i, options) + + i = skip_whitespace(text, new_i) + + if text:sub(i, i) ~= ':' then + self:onDecodeError("expected colon", text, i, options.etc) + return nil, i -- in case the error method doesn't abort, return something sensible + end + + i = skip_whitespace(text, i + 1) + + local new_val, new_i = grok_one(self, text, i, options) + + VALUE[key] = new_val + + -- + -- Expect now either '}' to end things, or a ',' to allow us to continue. + -- + i = skip_whitespace(text, new_i) + + local c = text:sub(i, i) + + if c == '}' then + return VALUE, i + 1 + end + + if text:sub(i, i) ~= ',' then + self:onDecodeError("expected comma or '}'", text, i, options.etc) + return nil, i -- in case the error method doesn't abort, return something sensible + end + + i = skip_whitespace(text, i + 1) + end + + self:onDecodeError("unclosed '{'", text, start, options.etc) + return nil, start -- in case the error method doesn't abort, return something sensible +end + +local function grok_array(self, text, start, options) + if text:sub(start, start) ~= '[' then + self:onDecodeError("expected '['", text, start, options.etc) + return nil, start -- in case the error method doesn't abort, return something sensible + end + + local i = skip_whitespace(text, start + 1) -- +1 to skip the '[' + local VALUE = self.strictTypes and self:newArray { } or { } + if text:sub(i, i) == ']' then + return VALUE, i + 1 + end + + local VALUE_INDEX = 1 + + local text_len = text:len() + while i <= text_len do + local val, new_i = grok_one(self, text, i, options) + + -- can't table.insert(VALUE, val) here because it's a no-op if val is nil + VALUE[VALUE_INDEX] = val + VALUE_INDEX = VALUE_INDEX + 1 + + i = skip_whitespace(text, new_i) + + -- + -- Expect now either ']' to end things, or a ',' to allow us to continue. + -- + local c = text:sub(i, i) + if c == ']' then + return VALUE, i + 1 + end + if text:sub(i, i) ~= ',' then + self:onDecodeError("expected comma or ']'", text, i, options.etc) + return nil, i -- in case the error method doesn't abort, return something sensible + end + i = skip_whitespace(text, i + 1) + end + self:onDecodeError("unclosed '['", text, start, options.etc) + return nil, i -- in case the error method doesn't abort, return something sensible +end + +grok_one = function(self, text, start, options) + -- Skip any whitespace + start = skip_whitespace(text, start) + + if start > text:len() then + self:onDecodeError("unexpected end of string", text, nil, options.etc) + return nil, start -- in case the error method doesn't abort, return something sensible + end + + if text:find('^"', start) then + return grok_string(self, text, start, options.etc) + + elseif text:find('^[-0123456789 ]', start) then + return grok_number(self, text, start, options) + + elseif text:find('^%{', start) then + return grok_object(self, text, start, options) + + elseif text:find('^%[', start) then + return grok_array(self, text, start, options) + + elseif text:find('^true', start) then + return true, start + 4 + + elseif text:find('^false', start) then + return false, start + 5 + + elseif text:find('^null', start) then + return options.null, start + 4 + + else + self:onDecodeError("can't parse JSON", text, start, options.etc) + return nil, 1 -- in case the error method doesn't abort, return something sensible + end +end + +function OBJDEF:decode(text, etc, options) + -- + -- If the user didn't pass in a table of decode options, make an empty one. + -- + if type(options) ~= 'table' then + options = {} + end + + -- + -- If they passed in an 'etc' argument, stuff it into the options. + -- (If not, any 'etc' field in the options they passed in remains to be used) + -- + if etc ~= nil then + options.etc = etc + end + + if type(self) ~= 'table' or self.__index ~= OBJDEF then + local error_message = "JSON:decode must be called in method format" + OBJDEF:onDecodeError(error_message, nil, nil, options.etc) + return nil, error_message -- in case the error method doesn't abort, return something sensible + end + + if text == nil then + local error_message = "nil passed to JSON:decode()" + self:onDecodeOfNilError(error_message, nil, nil, options.etc) + return nil, error_message -- in case the error method doesn't abort, return something sensible + + elseif type(text) ~= 'string' then + local error_message = "expected string argument to JSON:decode()" + self:onDecodeError(string.format("%s, got %s", error_message, type(text)), nil, nil, options.etc) + return nil, error_message -- in case the error method doesn't abort, return something sensible + end + + if text:match('^%s*$') then + -- an empty string is nothing, but not an error + return nil + end + + if text:match('^%s*<') then + -- Can't be JSON... we'll assume it's HTML + local error_message = "HTML passed to JSON:decode()" + self:onDecodeOfHTMLError(error_message, text, nil, options.etc) + return nil, error_message -- in case the error method doesn't abort, return something sensible + end + + -- + -- Ensure that it's not UTF-32 or UTF-16. + -- Those are perfectly valid encodings for JSON (as per RFC 4627 section 3), + -- but this package can't handle them. + -- + if text:sub(1, 1):byte() == 0 or (text:len() >= 2 and text:sub(2, 2):byte() == 0) then + local error_message = "JSON package groks only UTF-8, sorry" + self:onDecodeError(error_message, text, nil, options.etc) + return nil, error_message -- in case the error method doesn't abort, return something sensible + end + + -- + -- apply global options + -- + if options.decodeNumbersAsObjects == nil then + options.decodeNumbersAsObjects = self.decodeNumbersAsObjects + end + if options.decodeIntegerObjectificationLength == nil then + options.decodeIntegerObjectificationLength = self.decodeIntegerObjectificationLength + end + if options.decodeDecimalObjectificationLength == nil then + options.decodeDecimalObjectificationLength = self.decodeDecimalObjectificationLength + end + if options.decodeIntegerStringificationLength == nil then + options.decodeIntegerStringificationLength = self.decodeIntegerStringificationLength + end + if options.decodeDecimalStringificationLength == nil then + options.decodeDecimalStringificationLength = self.decodeDecimalStringificationLength + end + + + -- + -- Finally, go parse it + -- + local success, value, next_i = pcall(grok_one, self, text, 1, options) + + if success then + + local error_message = nil + if next_i ~= #text + 1 then + -- something's left over after we parsed the first thing.... whitespace is allowed. + next_i = skip_whitespace(text, next_i) + + -- if we have something left over now, it's trailing garbage + if next_i ~= #text + 1 then + value, error_message = self:onTrailingGarbage(text, next_i, value, options.etc) + end + end + return value, error_message + + else + + -- If JSON:onDecodeError() didn't abort out of the pcall, we'll have received + -- the error message here as "value", so pass it along as an assert. + local error_message = value + if self.assert then + self.assert(false, error_message) + else + assert(false, error_message) + end + -- ...and if we're still here (because the assert didn't throw an error), + -- return a nil and throw the error message on as a second arg + return nil, error_message + + end +end + +local function backslash_replacement_function(c) + if c == "\n" then + return "\\n" + elseif c == "\r" then + return "\\r" + elseif c == "\t" then + return "\\t" + elseif c == "\b" then + return "\\b" + elseif c == "\f" then + return "\\f" + elseif c == '"' then + return '\\"' + elseif c == '\\' then + return '\\\\' + else + return string.format("\\u%04x", c:byte()) + end +end + +local chars_to_be_escaped_in_JSON_string = '[' + .. '"' -- class sub-pattern to match a double quote + .. '%\\' -- class sub-pattern to match a backslash + .. '%z' -- class sub-pattern to match a null + .. '\001' .. '-' .. '\031' -- class sub-pattern to match control characters + .. ']' + +local LINE_SEPARATOR_as_utf8 = unicode_codepoint_as_utf8(0x2028) +local PARAGRAPH_SEPARATOR_as_utf8 = unicode_codepoint_as_utf8(0x2029) +local function json_string_literal(value, options) + local newval = value:gsub(chars_to_be_escaped_in_JSON_string, backslash_replacement_function) + if options.stringsAreUtf8 then + -- + -- This feels really ugly to just look into a string for the sequence of bytes that we know to be a particular utf8 character, + -- but utf8 was designed purposefully to make this kind of thing possible. Still, feels dirty. + -- I'd rather decode the byte stream into a character stream, but it's not technically needed so + -- not technically worth it. + -- + newval = newval:gsub(LINE_SEPARATOR_as_utf8, '\\u2028'):gsub(PARAGRAPH_SEPARATOR_as_utf8, '\\u2029') + end + return '"' .. newval .. '"' +end + +local function object_or_array(self, T, etc) + -- + -- We need to inspect all the keys... if there are any strings, we'll convert to a JSON + -- object. If there are only numbers, it's a JSON array. + -- + -- If we'll be converting to a JSON object, we'll want to sort the keys so that the + -- end result is deterministic. + -- + local string_keys = { } + local number_keys = { } + local number_keys_must_be_strings = false + local maximum_number_key + + for key in pairs(T) do + if type(key) == 'string' then + table.insert(string_keys, key) + elseif type(key) == 'number' then + table.insert(number_keys, key) + if key <= 0 or key >= math.huge then + number_keys_must_be_strings = true + elseif not maximum_number_key or key > maximum_number_key then + maximum_number_key = key + end + elseif type(key) == 'boolean' then + table.insert(string_keys, tostring(key)) + else + self:onEncodeError("can't encode table with a key of type " .. type(key), etc) + end + end + + if #string_keys == 0 and not number_keys_must_be_strings then + -- + -- An empty table, or a numeric-only array + -- + if #number_keys > 0 then + return nil, maximum_number_key -- an array + elseif tostring(T) == "JSON array" then + return nil + elseif tostring(T) == "JSON object" then + return { } + else + -- have to guess, so we'll pick array, since empty arrays are likely more common than empty objects + return nil + end + end + + table.sort(string_keys) + + local map + if #number_keys > 0 then + -- + -- If we're here then we have either mixed string/number keys, or numbers inappropriate for a JSON array + -- It's not ideal, but we'll turn the numbers into strings so that we can at least create a JSON object. + -- + + if self.noKeyConversion then + self:onEncodeError("a table with both numeric and string keys could be an object or array; aborting", etc) + end + + -- + -- Have to make a shallow copy of the source table so we can remap the numeric keys to be strings + -- + map = { } + for key, val in pairs(T) do + map[key] = val + end + + table.sort(number_keys) + + -- + -- Throw numeric keys in there as strings + -- + for _, number_key in ipairs(number_keys) do + local string_key = tostring(number_key) + if map[string_key] == nil then + table.insert(string_keys, string_key) + map[string_key] = T[number_key] + else + self:onEncodeError("conflict converting table with mixed-type keys into a JSON object: key " .. number_key .. " exists both as a string and a number.", etc) + end + end + end + + return string_keys, nil, map +end + +-- +-- Encode +-- +-- 'options' is nil, or a table with possible keys: +-- +-- pretty -- If true, return a pretty-printed version. +-- +-- indent -- A string (usually of spaces) used to indent each nested level. +-- +-- align_keys -- If true, align all the keys when formatting a table. The result is uglier than one might at first imagine. +-- Results are undefined if 'align_keys' is true but 'pretty' is not. +-- +-- array_newline -- If true, array elements are formatted each to their own line. The default is to all fall inline. +-- Results are undefined if 'array_newline' is true but 'pretty' is not. +-- +-- null -- If this exists with a string value, table elements with this value are output as JSON null. +-- +-- stringsAreUtf8 -- If true, consider Lua strings not as a sequence of bytes, but as a sequence of UTF-8 characters. +-- (Currently, the only practical effect of setting this option is that Unicode LINE and PARAGRAPH +-- separators, if found in a string, are encoded with a JSON escape instead of as raw UTF-8. +-- The JSON is valid either way, but encoding this way, apparently, allows the resulting JSON +-- to also be valid Java.) +-- +-- +local function encode_value(self, value, parents, etc, options, indent, for_key) + + -- + -- keys in a JSON object can never be null, so we don't even consider options.null when converting a key value + -- + if value == nil or (not for_key and options and options.null and value == options.null) then + return 'null' + + elseif type(value) == 'string' then + return json_string_literal(value, options) + + elseif type(value) == 'number' then + if value ~= value then + -- + -- NaN (Not a Number). + -- JSON has no NaN, so we have to fudge the best we can. This should really be a package option. + -- + return "null" + elseif value >= math.huge then + -- + -- Positive infinity. JSON has no INF, so we have to fudge the best we can. This should + -- really be a package option. Note: at least with some implementations, positive infinity + -- is both ">= math.huge" and "<= -math.huge", which makes no sense but that's how it is. + -- Negative infinity is properly "<= -math.huge". So, we must be sure to check the ">=" + -- case first. + -- + return "1e+9999" + elseif value <= -math.huge then + -- + -- Negative infinity. + -- JSON has no INF, so we have to fudge the best we can. This should really be a package option. + -- + return "-1e+9999" + else + return tostring(value) + end + + elseif type(value) == 'boolean' then + return tostring(value) + + elseif type(value) ~= 'table' then + + if self.unsupportedTypeEncoder then + local user_value, user_error = self:unsupportedTypeEncoder(value, parents, etc, options, indent, for_key) + -- If the user's handler returns a string, use that. If it returns nil plus an error message, bail with that. + -- If only nil returned, fall through to the default error handler. + if type(user_value) == 'string' then + return user_value + elseif user_value ~= nil then + self:onEncodeError("unsupportedTypeEncoder method returned a " .. type(user_value), etc) + elseif user_error then + self:onEncodeError(tostring(user_error), etc) + end + end + + self:onEncodeError("can't convert " .. type(value) .. " to JSON", etc) + + elseif getmetatable(value) == isNumber then + return tostring(value) + else + -- + -- A table to be converted to either a JSON object or array. + -- + local T = value + + if type(options) ~= 'table' then + options = {} + end + if type(indent) ~= 'string' then + indent = "" + end + + if parents[T] then + self:onEncodeError("table " .. tostring(T) .. " is a child of itself", etc) + else + parents[T] = true + end + + local result_value + + local object_keys, maximum_number_key, map = object_or_array(self, T, etc) + if maximum_number_key then + -- + -- An array... + -- + local key_indent + if options.array_newline then + key_indent = indent .. tostring(options.indent or "") + else + key_indent = indent + end + + local ITEMS = { } + for i = 1, maximum_number_key do + table.insert(ITEMS, encode_value(self, T[i], parents, etc, options, key_indent)) + end + + if options.array_newline then + result_value = "[\n" .. key_indent .. table.concat(ITEMS, ",\n" .. key_indent) .. "\n" .. indent .. "]" + elseif options.pretty then + result_value = "[ " .. table.concat(ITEMS, ", ") .. " ]" + else + result_value = "[" .. table.concat(ITEMS, ",") .. "]" + end + + elseif object_keys then + -- + -- An object + -- + local TT = map or T + + if options.pretty then + + local KEYS = { } + local max_key_length = 0 + for _, key in ipairs(object_keys) do + local encoded = encode_value(self, tostring(key), parents, etc, options, indent, true) + if options.align_keys then + max_key_length = math.max(max_key_length, #encoded) + end + table.insert(KEYS, encoded) + end + local key_indent = indent .. tostring(options.indent or "") + local subtable_indent = key_indent .. string.rep(" ", max_key_length) .. (options.align_keys and " " or "") + local FORMAT = "%s%" .. string.format("%d", max_key_length) .. "s: %s" + + local COMBINED_PARTS = { } + for i, key in ipairs(object_keys) do + local encoded_val = encode_value(self, TT[key], parents, etc, options, subtable_indent) + table.insert(COMBINED_PARTS, string.format(FORMAT, key_indent, KEYS[i], encoded_val)) + end + result_value = "{\n" .. table.concat(COMBINED_PARTS, ",\n") .. "\n" .. indent .. "}" + + else + + local PARTS = { } + for _, key in ipairs(object_keys) do + local encoded_val = encode_value(self, TT[key], parents, etc, options, indent) + local encoded_key = encode_value(self, tostring(key), parents, etc, options, indent, true) + table.insert(PARTS, string.format("%s:%s", encoded_key, encoded_val)) + end + result_value = "{" .. table.concat(PARTS, ",") .. "}" + + end + else + -- + -- An empty array/object... we'll treat it as an array, though it should really be an option + -- + result_value = "[]" + end + + parents[T] = false + return result_value + end +end + +local function top_level_encode(self, value, etc, options) + local val = encode_value(self, value, {}, etc, options) + if val == nil then + --PRIVATE("may need to revert to the previous public verison if I can't figure out what the guy wanted") + return val + else + return val + end +end + +function OBJDEF:encode(value, etc, options) + if type(self) ~= 'table' or self.__index ~= OBJDEF then + OBJDEF:onEncodeError("JSON:encode must be called in method format", etc) + end + + -- + -- If the user didn't pass in a table of decode options, make an empty one. + -- + if type(options) ~= 'table' then + options = {} + end + + return top_level_encode(self, value, etc, options) +end + +function OBJDEF:encode_pretty(value, etc, options) + if type(self) ~= 'table' or self.__index ~= OBJDEF then + OBJDEF:onEncodeError("JSON:encode_pretty must be called in method format", etc) + end + + -- + -- If the user didn't pass in a table of decode options, use the default pretty ones + -- + if type(options) ~= 'table' then + options = default_pretty_options + end + + return top_level_encode(self, value, etc, options) +end + +function OBJDEF.__tostring() + return "JSON encode/decode package" +end + +OBJDEF.__index = OBJDEF + +function OBJDEF:new(args) + local new = { } + + if args then + for key, val in pairs(args) do + new[key] = val + end + end + + return setmetatable(new, OBJDEF) +end + +return OBJDEF:new() + +-- +-- Version history: +-- +-- 20170927.26 Use option.null in decoding as well. Thanks to Max Sindwani for the bump, and sorry to Oliver Hitz +-- whose first mention of it four years ago was completely missed by me. +-- +-- 20170823.25 Added support for JSON:unsupportedTypeEncoder(). +-- Thanks to Chronos Phaenon Eosphoros (https://github.com/cpeosphoros) for the idea. +-- +-- 20170819.24 Added support for boolean keys in tables. +-- +-- 20170416.23 Added the "array_newline" formatting option suggested by yurenchen (http://www.yurenchen.com/) +-- +-- 20161128.22 Added: +-- JSON:isString() +-- JSON:isNumber() +-- JSON:decodeIntegerObjectificationLength +-- JSON:decodeDecimalObjectificationLength +-- +-- 20161109.21 Oops, had a small boo-boo in the previous update. +-- +-- 20161103.20 Used to silently ignore trailing garbage when decoding. Now fails via JSON:onTrailingGarbage() +-- http://seriot.ch/parsing_json.php +-- +-- Built-in error message about "expected comma or ']'" had mistakenly referred to '[' +-- +-- Updated the built-in error reporting to refer to bytes rather than characters. +-- +-- The decode() method no longer assumes that error handlers abort. +-- +-- Made the VERSION string a string instead of a number +-- + +-- 20160916.19 Fixed the isNumber.__index assignment (thanks to Jack Taylor) +-- +-- 20160730.18 Added JSON:forceString() and JSON:forceNumber() +-- +-- 20160728.17 Added concatenation to the metatable for JSON:asNumber() +-- +-- 20160709.16 Could crash if not passed an options table (thanks jarno heikkinen ). +-- +-- Made JSON:asNumber() a bit more resilient to being passed the results of itself. +-- +-- 20160526.15 Added the ability to easily encode null values in JSON, via the new "null" encoding option. +-- (Thanks to Adam B for bringing up the issue.) +-- +-- Added some support for very large numbers and precise floats via +-- JSON.decodeNumbersAsObjects +-- JSON.decodeIntegerStringificationLength +-- JSON.decodeDecimalStringificationLength +-- +-- Added the "stringsAreUtf8" encoding option. (Hat tip to http://lua-users.org/wiki/JsonModules ) +-- +-- 20141223.14 The encode_pretty() routine produced fine results for small datasets, but isn't really +-- appropriate for anything large, so with help from Alex Aulbach I've made the encode routines +-- more flexible, and changed the default encode_pretty() to be more generally useful. +-- +-- Added a third 'options' argument to the encode() and encode_pretty() routines, to control +-- how the encoding takes place. +-- +-- Updated docs to add assert() call to the loadfile() line, just as good practice so that +-- if there is a problem loading JSON.lua, the appropriate error message will percolate up. +-- +-- 20140920.13 Put back (in a way that doesn't cause warnings about unused variables) the author string, +-- so that the source of the package, and its version number, are visible in compiled copies. +-- +-- 20140911.12 Minor lua cleanup. +-- Fixed internal reference to 'JSON.noKeyConversion' to reference 'self' instead of 'JSON'. +-- (Thanks to SmugMug's David Parry for these.) +-- +-- 20140418.11 JSON nulls embedded within an array were being ignored, such that +-- ["1",null,null,null,null,null,"seven"], +-- would return +-- {1,"seven"} +-- It's now fixed to properly return +-- {1, nil, nil, nil, nil, nil, "seven"} +-- Thanks to "haddock" for catching the error. +-- +-- 20140116.10 The user's JSON.assert() wasn't always being used. Thanks to "blue" for the heads up. +-- +-- 20131118.9 Update for Lua 5.3... it seems that tostring(2/1) produces "2.0" instead of "2", +-- and this caused some problems. +-- +-- 20131031.8 Unified the code for encode() and encode_pretty(); they had been stupidly separate, +-- and had of course diverged (encode_pretty didn't get the fixes that encode got, so +-- sometimes produced incorrect results; thanks to Mattie for the heads up). +-- +-- Handle encoding tables with non-positive numeric keys (unlikely, but possible). +-- +-- If a table has both numeric and string keys, or its numeric keys are inappropriate +-- (such as being non-positive or infinite), the numeric keys are turned into +-- string keys appropriate for a JSON object. So, as before, +-- JSON:encode({ "one", "two", "three" }) +-- produces the array +-- ["one","two","three"] +-- but now something with mixed key types like +-- JSON:encode({ "one", "two", "three", SOMESTRING = "some string" })) +-- instead of throwing an error produces an object: +-- {"1":"one","2":"two","3":"three","SOMESTRING":"some string"} +-- +-- To maintain the prior throw-an-error semantics, set +-- JSON.noKeyConversion = true +-- +-- 20131004.7 Release under a Creative Commons CC-BY license, which I should have done from day one, sorry. +-- +-- 20130120.6 Comment update: added a link to the specific page on my blog where this code can +-- be found, so that folks who come across the code outside of my blog can find updates +-- more easily. +-- +-- 20111207.5 Added support for the 'etc' arguments, for better error reporting. +-- +-- 20110731.4 More feedback from David Kolf on how to make the tests for Nan/Infinity system independent. +-- +-- 20110730.3 Incorporated feedback from David Kolf at http://lua-users.org/wiki/JsonModules: +-- +-- * When encoding lua for JSON, Sparse numeric arrays are now handled by +-- spitting out full arrays, such that +-- JSON:encode({"one", "two", [10] = "ten"}) +-- returns +-- ["one","two",null,null,null,null,null,null,null,"ten"] +-- +-- In 20100810.2 and earlier, only up to the first non-null value would have been retained. +-- +-- * When encoding lua for JSON, numeric value NaN gets spit out as null, and infinity as "1+e9999". +-- Version 20100810.2 and earlier created invalid JSON in both cases. +-- +-- * Unicode surrogate pairs are now detected when decoding JSON. +-- +-- 20100810.2 added some checking to ensure that an invalid Unicode character couldn't leak in to the UTF-8 encoding +-- +-- 20100731.1 initial public release +-- diff --git a/lua/ReferenceMeteo.json b/lua/ReferenceMeteo.json new file mode 100755 index 0000000..0d618e7 --- /dev/null +++ b/lua/ReferenceMeteo.json @@ -0,0 +1,94 @@ + +{ + "response": { + "version":"0.1", + "termsofService":"http://www.wunderground.com/weather/api/d/terms.html", + "features": { + "conditions": 1 + } + } + , "current_observation": { + "image": { + "url":"http://icons.wxug.com/graphics/wu2/logo_130x80.png", + "title":"Weather Underground", + "link":"http://www.wunderground.com" + }, + "display_location": { + "full":"Redon, France", + "city":"Redon", + "state":"35", + "state_name":"France", + "country":"FR", + "country_iso3166":"FR", + "zip":"00000", + "magic":"274", + "wmo":"07217", + "latitude":"47.65000153", + "longitude":"-2.07999992", + "elevation":"25.0" + }, + "observation_location": { + "full":"Plessé, Plessé, ", + "city":"Plessé, Plessé", + "state":"", + "country":"FR", + "country_iso3166":"FR", + "latitude":"47.573772", + "longitude":"-1.954625", + "elevation":"0 ft" + }, + "estimated": { + }, + "station_id":"IPLESS6", + "observation_time":"Last Updated on September 24, 12:08 PM CEST", + "observation_time_rfc822":"Sun, 24 Sep 2017 12:08:56 +0200", + "observation_epoch":"1506247736", + "local_time_rfc822":"Sun, 24 Sep 2017 12:10:00 +0200", + "local_epoch":"1506247800", + "local_tz_short":"CEST", + "local_tz_long":"Europe/Paris", + "local_tz_offset":"+0200", + "weather":"Overcast", + "temperature_string":"62.1 F (16.7 C)", + "temp_f":62.1, + "temp_c":16.7, + "relative_humidity":"94%", + "wind_string":"Calm", + "wind_dir":"SW", + "wind_degrees":232, + "wind_mph":0.6, + "wind_gust_mph":"2.5", + "wind_kph":1.0, + "wind_gust_kph":"4.0", + "pressure_mb":"1019", + "pressure_in":"30.09", + "pressure_trend":"+", + "dewpoint_string":"60 F (16 C)", + "dewpoint_f":60, + "dewpoint_c":16, + "heat_index_string":"NA", + "heat_index_f":"NA", + "heat_index_c":"NA", + "windchill_string":"NA", + "windchill_f":"NA", + "windchill_c":"NA", + "feelslike_string":"62.1 F (16.7 C)", + "feelslike_f":"62.1", + "feelslike_c":"16.7", + "visibility_mi":"6.2", + "visibility_km":"10.0", + "solarradiation":"--", + "UV":"2","precip_1hr_string":"-999.00 in ( 0 mm)", + "precip_1hr_in":"-999.00", + "precip_1hr_metric":" 0", + "precip_today_string":"0.00 in (0 mm)", + "precip_today_in":"0.00", + "precip_today_metric":"0", + "icon":"cloudy", + "icon_url":"http://icons.wxug.com/i/c/k/cloudy.gif", + "forecast_url":"http://www.wunderground.com/global/stations/07217.html", + "history_url":"http://www.wunderground.com/weatherstation/WXDailyHistory.asp?ID=IPLESS6", + "ob_url":"http://www.wunderground.com/cgi-bin/findweather/getForecast?query=47.573772,-1.954625", + "nowcast":"" + } +} diff --git a/lua/XmlParser.lua b/lua/XmlParser.lua new file mode 100644 index 0000000..e0ea0a0 --- /dev/null +++ b/lua/XmlParser.lua @@ -0,0 +1,437 @@ +--- @module Class providing the actual XML parser. +-- Available options are: +-- * stripWS +-- Strip non-significant whitespace (leading/trailing) +-- and do not generate events for empty text elements +-- +-- * expandEntities +-- Expand entities (standard entities + single char +-- numeric entities only currently - could be extended +-- at runtime if suitable DTD parser added elements +-- to table (see obj._ENTITIES). May also be possible +-- to expand multibyre entities for UTF-8 only +-- +-- * errorHandler +-- Custom error handler function +-- +-- NOTE: Boolean options must be set to 'nil' not '0' + +---Converts the decimal code of a character to its corresponding char +--if it's a graphical char, otherwise, returns the HTML ISO code +--for that decimal value in the format &#code +--@param code the decimal value to convert to its respective character +local function decimalToHtmlChar(code) + local n = tonumber(code) + if n >= 0 and n < 256 then + return string.char(n) + else + return "&#"..code..";" + end +end + +---Converts the hexadecimal code of a character to its corresponding char +--if it's a graphical char, otherwise, returns the HTML ISO code +--for that hexadecimal value in the format ode +--@param code the hexadecimal value to convert to its respective character +local function hexadecimalToHtmlChar(code) + local n = tonumber(code, 16) + if n >= 0 and n < 256 then + return string.char(n) + else + return "&#x"..code..";" + end +end + +local XmlParser = { + -- Private attribures/functions + _XML = '^([^<]*)<(%/?)([^>]-)(%/?)>', + _ATTR1 = '([%w-:_]+)%s*=%s*"(.-)"', + _ATTR2 = '([%w-:_]+)%s*=%s*\'(.-)\'', + _CDATA = '<%!%[CDATA%[(.-)%]%]>', + _PI = '<%?(.-)%?>', + _COMMENT = '', + _TAG = '^(.-)%s.*', + _LEADINGWS = '^%s+', + _TRAILINGWS = '%s+$', + _WS = '^%s*$', + _DTD1 = '', + _DTD2 = '', + --_DTD3 = '', + _DTD3 = '', + _DTD4 = '', + _DTD5 = '', + + --Matches an attribute with non-closing double quotes (The equal sign is matched non-greedly by using =+?) + _ATTRERR1 = '=+?%s*"[^"]*$', + --Matches an attribute with non-closing single quotes (The equal sign is matched non-greedly by using =+?) + _ATTRERR2 = '=+?%s*\'[^\']*$', + --Matches a closing tag such as or the end of a openning tag such as + _TAGEXT = '(%/?)>', + + _errstr = { + xmlErr = "Error Parsing XML", + declErr = "Error Parsing XMLDecl", + declStartErr = "XMLDecl not at start of document", + declAttrErr = "Invalid XMLDecl attributes", + piErr = "Error Parsing Processing Instruction", + commentErr = "Error Parsing Comment", + cdataErr = "Error Parsing CDATA", + dtdErr = "Error Parsing DTD", + endTagErr = "End Tag Attributes Invalid", + unmatchedTagErr = "Unbalanced Tag", + incompleteXmlErr = "Incomplete XML Document", + }, + + _ENTITIES = { + ["<"] = "<", + [">"] = ">", + ["&"] = "&", + ["""] = '"', + ["'"] = "'", + ["&#(%d+);"] = decimalToHtmlChar, + ["&#x(%x+);"] = hexadecimalToHtmlChar, + }, +} + +--- Instantiates a XmlParser object. +--@param _handler Handler module to be used to convert the XML string +-- to another formats. See the available handlers at the handler directory. +-- Usually you get an instance to a handler module using, for instance: +-- local handler = require("xmlhandler/tree"). +--@param _options Options for this XmlParser instance. +--@see XmlParser.options +function XmlParser.new(_handler, _options) + local obj = { + handler = _handler, + options = _options, + _stack = {} + } + + setmetatable(obj, XmlParser) + obj.__index = XmlParser + return obj; +end + +---Checks if a function/field exists in a table or in its metatable +--@param table the table to check if it has a given function +--@param elementName the name of the function/field to check if exists +--@return true if the function/field exists, false otherwise +local function fexists(table, elementName) + if table == nil then + return false + end + + if table[elementName] ~= nil then + return true + else + return fexists(getmetatable(table), elementName) + end +end + +local function err(self, err, pos) + if self.options.errorHandler then + self.options.errorHandler(err,pos) + end +end + +--- Removes whitespaces +local function stripWS(self, s) + if self.options.stripWS then + s = string.gsub(s,'^%s+','') + s = string.gsub(s,'%s+$','') + end + return s +end + +local function parseEntities(self, s) + if self.options.expandEntities then + for k,v in pairs(self._ENTITIES) do + s = string.gsub(s,k,v) + end + end + + return s +end + +--- Parses a string representing a tag. +--@param s String containing tag text +--@return a {name, attrs} table +-- where name is the name of the tag and attrs +-- is a table containing the atributtes of the tag +local function parseTag(self, s) + local tag = { + name = string.gsub(s, self._TAG, '%1'), + attrs = {} + } + + local parseFunction = function (k, v) + tag.attrs[k] = parseEntities(self, v) + tag.attrs._ = 1 + end + + string.gsub(s, self._ATTR1, parseFunction) + string.gsub(s, self._ATTR2, parseFunction) + + if tag.attrs._ then + tag.attrs._ = nil + else + tag.attrs = nil + end + + return tag +end + +local function parseXmlDeclaration(self, xml, f) + -- XML Declaration + f.match, f.endMatch, f.text = string.find(xml, self._PI, f.pos) + if not f.match then + err(self, self._errstr.declErr, f.pos) + end + + if f.match ~= 1 then + -- Must be at start of doc if present + err(self, self._errstr.declStartErr, f.pos) + end + + local tag = parseTag(self, f.text) + -- TODO: Check if attributes are valid + -- Check for version (mandatory) + if tag.attrs and tag.attrs.version == nil then + err(self, self._errstr.declAttrErr, f.pos) + end + + if fexists(self.handler, 'decl') then + self.handler:decl(tag, f.match, f.endMatch) + end + + return tag +end + +local function parseXmlProcessingInstruction(self, xml, f) + local tag = {} + + -- XML Processing Instruction (PI) + f.match, f.endMatch, f.text = string.find(xml, self._PI, f.pos) + if not f.match then + err(self, self._errstr.piErr, f.pos) + end + if fexists(self.handler, 'pi') then + -- Parse PI attributes & text + tag = parseTag(self, f.text) + local pi = string.sub(f.text, string.len(tag.name)+1) + if pi ~= "" then + if tag.attrs then + tag.attrs._text = pi + else + tag.attrs = { _text = pi } + end + end + self.handler:pi(tag, f.match, f.endMatch) + end + + return tag +end + +local function parseComment(self, xml, f) + f.match, f.endMatch, f.text = string.find(xml, self._COMMENT, f.pos) + if not f.match then + err(self, self._errstr.commentErr, f.pos) + end + + if fexists(self.handler, 'comment') then + f.text = parseEntities(self, stripWS(self, f.text)) + self.handler:comment(f.text, next, f.match, f.endMatch) + end +end + +local function _parseDtd(self, xml, pos) + -- match,endMatch,root,type,name,uri,internal + local dtdPatterns = {self._DTD1, self._DTD2, self._DTD3, self._DTD4, self._DTD5} + + for i, dtd in pairs(dtdPatterns) do + local m,e,r,t,n,u,i = string.find(xml, dtd, pos) + if m then + return m, e, {_root=r, _type=t, _name=n, _uri=u, _internal=i} + end + end + + return nil +end + +local function parseDtd(self, xml, f) + f.match, f.endMatch, attrs = _parseDtd(self, xml, f.pos) + if not f.match then + err(self, self._errstr.dtdErr, f.pos) + end + + if fexists(self.handler, 'dtd') then + local tag = {name="DOCTYPE", value=string.sub(xml, f.match+10, f.endMatch-1)} + self.handler:dtd(tag, f.match, f.endMatch) + end +end + +local function parseCdata(self, xml, f) + f.match, f.endMatch, f.text = string.find(xml, self._CDATA, f.pos) + if not f.match then + err(self, self._errstr.cdataErr, f.pos) + end + + if fexists(self.handler, 'cdata') then + self.handler:cdata(f.text, nil, f.match, f.endMatch) + end +end + +--- Parse a Normal tag +-- Need check for embedded '>' in attribute value and extend +-- match recursively if necessary eg. +local function parseNormalTag(self, xml, f) + --Check for errors + while 1 do + --If there isn't an attribute without closing quotes (single or double quotes) + --then breaks to follow the normal processing of the tag. + --Otherwise, try to find where the quotes close. + f.errStart, f.errEnd = string.find(f.tagstr, self._ATTRERR1) + + if f.errEnd == nil then + f.errStart, f.errEnd = string.find(f.tagstr, self._ATTRERR2) + if f.errEnd == nil then + break + end + end + + f.extStart, f.extEnd, f.endt2 = string.find(xml, self._TAGEXT, f.endMatch+1) + f.tagstr = f.tagstr .. string.sub(xml, f.endMatch, f.extEnd-1) + if not f.match then + err(self, self._errstr.xmlErr, f.pos) + end + f.endMatch = f.extEnd + end + + -- Extract tag name and attrs + local tag = parseTag(self, f.tagstr) + + if (f.endt1=="/") then + if fexists(self.handler, 'endtag') then + if tag.attrs then + -- Shouldn't have any attributes in endtag + err(self, string.format("%s (/%s)", self._errstr.endTagErr, tag.name), f.pos) + end + if table.remove(self._stack) ~= tag.name then + err(self, string.format("%s (/%s)", self._errstr.unmatchedTagErr, tag.name), f.pos) + end + self.handler:endtag(tag, f.match, f.endMatch) + end + else + table.insert(self._stack, tag.name) + if fexists(self.handler, 'starttag') then + self.handler:starttag(tag, f.match, f.endMatch) + end + --TODO: Tags com fechamento automático estão sendo + --retornadas como uma tabela, o que complica + --para a app NCLua tratar isso. É preciso + --fazer com que seja retornado um campo string vazio. + + -- Self-Closing Tag + if (f.endt2=="/") then + table.remove(self._stack) + if fexists(self.handler, 'endtag') then + self.handler:endtag(tag, f.match, f.endMatch) + end + end + end + + return tag +end + +local function parseTagType(self, xml, f) + -- Test for tag type + if string.find(string.sub(f.tagstr, 1, 5), "?xml%s") then + parseXmlDeclaration(self, xml, f) + elseif string.sub(f.tagstr, 1, 1) == "?" then + parseXmlProcessingInstruction(self, xml, f) + elseif string.sub(f.tagstr, 1, 3) == "!--" then + parseComment(self, xml, f) + elseif string.sub(f.tagstr, 1, 8) == "!DOCTYPE" then + parseDtd(self, xml, f) + elseif string.sub(f.tagstr, 1, 8) == "![CDATA[" then + parseCdata(self, xml, f) + else + parseNormalTag(self, xml, f) + end +end + +--- Get next tag (first pass - fix exceptions below). +--@return true if the next tag could be got, false otherwise +local function getNextTag(self, xml, f) + f.match, f.endMatch, f.text, f.endt1, f.tagstr, f.endt2 = string.find(xml, self._XML, f.pos) + if not f.match then + if string.find(xml, self._WS, f.pos) then + -- No more text - check document complete + if #self._stack ~= 0 then + err(self, self._errstr.incompleteXmlErr, f.pos) + else + return false + end + else + -- Unparsable text + err(self, self._errstr.xmlErr, f.pos) + end + end + + f.text = f.text or '' + f.tagstr = f.tagstr or '' + f.match = f.match or 0 + + return f.endMatch ~= nil +end + +--Main function which starts the XML parsing process +--@param xml the XML string to parse +--@param parseAttributes indicates if tag attributes should be parsed or not. +-- If omitted, the default value is true. +function XmlParser:parse(xml, parseAttributes) + if type(self) ~= "table" or getmetatable(self) ~= XmlParser then + error("You must call xmlparser:parse(parameters) instead of xmlparser.parse(parameters)") + end + + if parseAttributes == nil then + parseAttributes = true + end + + self.handler.parseAttributes = parseAttributes + + --Stores string.find results and parameters + --and other auxiliar variables + local f = { + --string.find return + match = 0, + endMatch = 0, + -- text, end1, tagstr, end2, + + --string.find parameters and auxiliar variables + pos = 1, + -- startText, endText, + -- errStart, errEnd, extStart, extEnd, + } + + while f.match do + if not getNextTag(self, xml, f) then + break + end + + -- Handle leading text + f.startText = f.match + f.endText = f.match + string.len(f.text) - 1 + f.match = f.match + string.len(f.text) + f.text = parseEntities(self, stripWS(self, f.text)) + if f.text ~= "" and fexists(self.handler, 'text') then + self.handler:text(f.text, nil, f.match, f.endText) + end + + parseTagType(self, xml, f) + f.pos = f.endMatch + 1 + end +end + +XmlParser.__index = XmlParser +return XmlParser diff --git a/lua/command.txt b/lua/command.txt new file mode 100644 index 0000000..ef34aad --- /dev/null +++ b/lua/command.txt @@ -0,0 +1,13 @@ + commandArray['Switch']='On' + commandArray['Scene:Livingroom']='On' + commandArray['Group:Kitchen']='Inactive' + commandArray['Keyfob']='Group On' + commandArray['DimmableDevice']='Set Level 50' + commandArray['Selector']='Set Level: 50' + commandArray['SendNotification']='subject#body#0' + commandArray['SendEmail']='subject#body#your@email.com' + commandArray['OpenURL']='www.yourdomain.com/api/movecamtopreset.cgi' + commandArray['Blinds']='On RANDOM 30' + commandArray['Porch Light']='On FOR 2' + commandArray['Variable:MyVar']='Some value' + commandArray['Variable:MyVar']='Some value AFTER 3' diff --git a/lua/fonctions2.lua b/lua/fonctions2.lua new file mode 100755 index 0000000..da5aec8 --- /dev/null +++ b/lua/fonctions2.lua @@ -0,0 +1,1053 @@ +--[[ + + + +bibliothèque de fonctions pour domoticz +utiles à la réalisation de scripts d'automation en langage lua + +/!\ certaines fonctions ne fonctionneront pas sous windows. + +copier ce qui se trouve entre les 2 lignes ci dessous, en début de tout vos script +pour charger ce fichier et pouvoir en utiliser les fonctions + + +-------------------------------------------------------------------------------------------------------- + + +-- chargement des modules (http://easydomoticz.com/forum/viewtopic.php?f=17&t=3940) +dofile('/home/pi/domoticz/scripts/lua/modules.lua') + +local debug = true -- true pour voir les logs dans la console log Dz ou false pour ne pas les voir + + +-------------------------------------------------------------------------------------------------------- + + +]] + + +-------------------------------- +------ USER SETTINGS ------ +-------------------------------- + +-- domoticz +domoticzIP = '192.168.1.3' --'127.0.0.1' +domoticzPORT = '81' +domoticzUSER = '' -- nom d'utilisateur +domoticzPSWD = '' -- mot de pass +domoticzPASSCODE = '' -- pour interrupteur protégés +domoticzURL = 'http://'..domoticzIP..':'..domoticzPORT + + + +-------------------------------- +------ END ------ +-------------------------------- + + +-- chemin vers le dossier lua et curl +if (package.config:sub(1,1) == '/') then + -- system linux + luaDir = debug.getinfo(1).source:match("@?(.*/)") + curl = '/usr/bin/curl -m 15 ' -- ne pas oublier l'espace à la fin +else + -- system windows + luaDir = string.gsub(debug.getinfo(1).source:match("@?(.*\\)"),'\\','\\\\') + -- download curl : https://bintray.com/vszakats/generic/download_file?file_path=curl-7.54.0-win32-mingw.7z + curl = 'c:\\Programs\\Curl\\curl.exe ' -- ne pas oublier l'espace à la fin +end + +-- chargement du fichier JSON.lua +json = assert(loadfile(luaDir..'JSON.lua'))() + +--time.hour ou time.min ou time.sec +--ex : if (time.hour == 17 and time.min == 05) then +time = os.date("*t") + +-- retourne l'heure actuelle ex: "12:45" +heure = string.sub(os.date("%X"), 1, 5) + +-- retourne la date ex: "01:01" +date = os.date("%d:%m") + +-- retourne l'heure du lever de soleil ex: "06:41" +leverSoleil = string.sub(os.date("!%X",60*timeofday['SunriseInMinutes']), 1, 5) + +-- retourne l'heure du coucher de soleil ex: "22:15" +coucherSoleil = string.sub(os.date("!%X",60*timeofday['SunsetInMinutes']), 1, 5) + +-- retourne le jour actuel en français ex: "mardi" +days = {"dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"} +jour = days[(os.date("%w")+1)] + +-- retourne VRAI si la semaine est paire +-- usage : +-- if semainePaire() then .. +function semainePaire() + local tm = os.time() + local function getYearBeginDayOfWeek() + yearBegin = os.time{year=os.date("*t",tm).year,month=1,day=1} + yearBeginDayOfWeek = tonumber(os.date("%w",yearBegin)) + -- sunday correct from 0 -> 7 + if(yearBeginDayOfWeek == 0) then yearBeginDayOfWeek = 7 end + return yearBeginDayOfWeek + end + local function getDayAdd() + yearBeginDayOfWeek = getYearBeginDayOfWeek(tm) + if(yearBeginDayOfWeek < 5 ) then + -- first day is week 1 + dayAdd = (yearBeginDayOfWeek - 2) + else + -- first day is week 52 or 53 + dayAdd = (yearBeginDayOfWeek - 9) + end + return dayAdd + end + dayOfYear = os.date("%j",tm) + dayAdd = getDayAdd(tm) + dayOfYearCorrected = dayOfYear + dayAdd + if(dayOfYearCorrected < 0) then + -- week of last year - decide if 52 or 53 + lastYearBegin = os.time{year=os.date("*t",tm).year-1,month=1,day=1} + lastYearEnd = os.time{year=os.date("*t",tm).year-1,month=12,day=31} + dayAdd = getDayAdd(lastYearBegin) + dayOfYear = dayOfYear + os.date("%j",lastYearEnd) + dayOfYearCorrected = dayOfYear + dayAdd + end + weekNum = math.floor((dayOfYearCorrected) / 7) + 1 + if( (dayOfYearCorrected > 0) and weekNum == 53) then + -- check if it is not considered as part of week 1 of next year + nextYearBegin = os.time{year=os.date("*t",tm).year+1,month=1,day=1} + yearBeginDayOfWeek = getYearBeginDayOfWeek(nextYearBegin) + if(yearBeginDayOfWeek < 5 ) then + weekNum = 1 + end + end + return weekNum%2 == 0 +end + + +-- il fait jour +dayTime = timeofday['Daytime'] +-- il fait nuit +nightTime = timeofday['Nighttime'] + +-- température +function getTemp(device) + return round(tonumber(otherdevices_temperature[device]),1) +end + +-- humidité +function getHum(device) + return round(tonumber(otherdevices_humidity[device]),1) +end + +-- humidité moyenne +function humMoy(device) + local monthLog = assert(io.popen(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..'/json.htm?range=month&sensor=temp&type=graph&idx='..otherdevices_idx[device]..'"')) + local list = monthLog:read('*all') + monthLog:close() + local data = ReverseTable(json:decode(list).result) + return(round(data[1].hu)) +end + +-- humidité absolue +function humAbs(t,hr) +-- https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/ +-- Formule pour calculer l'humidité absolue +-- Dans la formule ci-dessous, la température (T) est exprimée en degrés Celsius, l'humidité relative (hr) est exprimée en%, et e est la base des logarithmes naturels 2.71828 [élevée à la puissance du contenu des crochets]: +-- Humidité absolue (grammes / m3 ) = (6,122 * e^[(17,67 * T) / (T + 243,5)] * rh * 2,1674))/(273,15 + T) +-- Cette formule est précise à 0,1% près, dans la gamme de température de -30 ° C à + 35 ° C + return round((6.112 * math.exp((17.67 * t)/(t+243.5)) * hr * 2.1674)/ (273.15 + t),1) +end + +-- set setpoint (faster way) +function setPoint(device,value) + os.execute(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..'/json.htm?type=command¶m=udevice&idx='..otherdevices_idx[device]..'&nvalue=0&svalue='..value..'" &') +end + +function dimUp15(device) + -- 15 step + switchOn(device, constrain(otherdevices_svalues[device]+1,1,15)) +end + +function dimDown15(device) + -- 15 step + switchOn(device, constrain(otherdevices_svalues[device]-1,1,15)) +end + +function dimUp(device) + -- 100 step + switchOn(device, constrain(otherdevices_svalues[device]+10,10,100)) +end + +function dimDown(device) + -- 100 step + switchOn(device, constrain(otherdevices_svalues[device]-10,10,100)) +end + +-- vérifie s'il y a eu changement d'état +function stateChange(device) + if (uservariables['lastState_'..device] == nil) then + creaVar('lastState_'..device,otherdevices[device]) + log('stateChange : création variable manquante lastState_'..device,debug) + return false + elseif (devicechanged[device] == nil) then + return false + elseif (devicechanged[device] == uservariables['lastState_'..device]) then + return false + else + duree = lastSeen(uservariables_lastupdate['lastState_'..device]) + updateVar('lastState_'..device,otherdevices[device]) + return otherdevices[device] + end +end + +-- convertion degrés en direction cardinale +function wind_cardinals(deg) + local cardinalDirections = { + ['N'] = {348.75, 360}, + ['N'] = {0, 11.25}, + ['NNE'] = {11.25, 33.75}, + ['NE'] = {33.75, 56.25}, + ['ENE'] = {56.25, 78.75}, + ['E'] = {78.75, 101.25}, + ['ESE'] = {101.25, 123.75}, + ['SE'] = {123.75, 146.25}, + ['SSE'] = {146.25, 168.75}, + ['S'] = {168.75, 191.25}, + ['SSW'] = {191.25, 213.75}, + ['SW'] = {213.75, 236.25}, + ['WSW'] = {236.25, 258.75}, + ['W'] = {258.75, 281.25}, + ['WNW'] = {281.25, 303.75}, + ['NW'] = {303.75, 326.25}, + ['NNW'] = {326.25, 348.75} + } + local cardinal + for dir, angle in pairs(cardinalDirections) do + if (deg >= angle[1] and deg < angle[2]) then + cardinal = dir + break + end + end + return cardinal +end + +-- dump all variables supplied to the script +-- usage +-- LogVariables(_G,0,'') +function LogVariables(x,depth,name) + for k,v in pairs(x) do + if (depth>0) or ((string.find(k,'device')~=nil) or (string.find(k,'variable')~=nil) or + (string.sub(k,1,4)=='time') or (string.sub(k,1,8)=='security')) then + if type(v)=="string" then print(name.."['"..k.."'] = '"..v.."'") end + if type(v)=="number" then print(name.."['"..k.."'] = "..v) end + if type(v)=="boolean" then print(name.."['"..k.."'] = "..tostring(v)) end + if type(v)=="table" then LogVariables(v,depth+1,k); end + end + end +end + +-- os.execute() output or web page content return +-- usage +-- local resultat = os.capture(cmd , true) +-- print('resultat: ' .. resultat) +function os.capture(cmd, raw) + local f = assert(io.popen(cmd, 'r')) + local s = assert(f:read('*a')) + f:close() + if raw then return s end + s = string.gsub(s, '^%s+', '') + s = string.gsub(s, '%s+$', '') + s = string.gsub(s, '[\n\r]+', ' ') + return s +end + +-- retourne le type de la variable +-- 'string' , 'number' , 'table' +function typeof(var) + local _type = type(var); + if(_type ~= "table" and _type ~= "userdata") then + return _type; + end + local _meta = getmetatable(var); + if(_meta ~= nil and _meta._NAME ~= nil) then + return _meta._NAME; + else + return _type; + end +end + +-- affiche les logs en bleu sauf si debug est spécifié à false +function log(txt,debug) + if (debug ~= false) then + --print(""..txt.."") + print(txt) + end +end + +-- affiche les logs en rouge sauf si debug est spécifié à false +function warn(txt,debug) + if (debug ~= false) then + --print(""..txt.."") + print(txt) + end +end + +-- écriture dans un fichier texte dans le dossier lua +function logToFile(fileName,data) + f = assert(io.open(luaDir..fileName..'.txt',"a")) + f:write(os.date("%c")..' '..data..'\n') + f:close() +end + +-- teste l'existance d'un fichier +function file_exists(file) + local f = io.open(file, "rb") + if f then f:close() end + return f ~= nil +end + +-- retourne le nom du switch selon son IDX +function getDeviceName(deviceIDX) + for i, v in pairs(otherdevices_idx) do + if v == deviceIDX then + return i + end + end + return 0 +end + +-- get all lines from a file, returns an empty +-- list/table if the file does not exist +function lines_from(file) + if not file_exists(luaDir..file..'.txt') then return {} end + lines = {} + for line in io.lines(luaDir..file..'.txt') do + lines[#lines + 1] = line + end + return lines +end + +-- encode du texte pour le passer dans une url +function url_encode(str) + if (str) then + str = string.gsub (str, "\n", "\r\n") + str = string.gsub (str, "([^%w %-%_%.%~])", + function (c) return string.format ("%%%02X", string.byte(c)) end) + str = string.gsub (str, " ", "+") + end + return str +end + +-- supprime les accents de la chaîne +function sans_accent(str) + if (str) then + str = string.gsub (str,"Ç", "C") + str = string.gsub (str,"ç", "c") + str = string.gsub (str,"[-èéêë']+", "e") + str = string.gsub (str,"[-ÈÉÊË']+", "E") + str = string.gsub (str,"[-àáâãäå']+", "a") + str = string.gsub (str,"[-@ÀÁÂÃÄÅ']+", "A") + str = string.gsub (str,"[-ìíîï']+", "i") + str = string.gsub (str,"[-ÌÍÎÏ']+", "I") + str = string.gsub (str,"[-ðòóôõö']+", "o") + str = string.gsub (str,"[-ÒÓÔÕÖ']+", "O") + str = string.gsub (str,"[-ùúûü']+", "u") + str = string.gsub (str,"[-ÙÚÛÜ']+", "U") + str = string.gsub (str,"[-ýÿ']+", "y") + str = string.gsub (str,"Ý", "Y") + end + return str +end + +-- retourne le temps en seconde depuis la dernière maj du péréphérique +function lastSeen(device) + timestamp = otherdevices_lastupdate[device] or device + y, m, d, H, M, S = timestamp:match("(%d+)-(%d+)-(%d+) (%d+):(%d+):(%d+)") + difference = os.difftime(os.time(), os.time{year=y, month=m, day=d, hour=H, min=M, sec=S}) + return difference +end + +-- contraindre +function constrain(x, a, b) + if (x < a) then + return a + elseif (x > b) then + return b + else + return x + end +end + +-- arrondire +function round(num, dec) + if num == 0 then + return 0 + else + local mult = 10^(dec or 0) + return math.floor(num * mult + 0.5) / mult + end +end + +-- met le script en pause (fortement déconseillé) +-- usage +-- sleep(10) -- pour mettre en pause 10 secondes +function sleep(n) + os.execute('sleep '..n) +end + +-- création de variable utilisateur +-- usage +-- creaVar('toto','10') -- pour créer une variable nommée toto comprenant la valeur 10 +function creaVar(name,value) + local api = '/json.htm?type=command¶m=adduservariable' + local name = '&vname='..url_encode(name) + local vtype = '&vtype=2' + local value = '&vvalue='..url_encode(value) + api = api..name..vtype..value + os.execute(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..api..'" &') +end + +-- update an existing variable +function updateVar(name,value) + local api = '/json.htm?type=command¶m=updateuservariable' + local name = '&vname='..url_encode(name) + local vtype = '&vtype=2' + local value = '&vvalue='..url_encode(value) + api = api..name..vtype..value + os.execute(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..api..'" &') +end + +-- envoie dans un capteur text une chaîne de caractères +-- le text sera intercepté et lu par la custom page grâce à sa fonction MQTT +-- usage +-- speak('tts','bonjour nous sommes dimanche') +function speak(TTSDeviceName,txt) + commandArray[#commandArray+1] = {['OpenURL'] = domoticzIP..":"..domoticzPORT..'/json.htm?type=command¶m=udevice&idx='..otherdevices_idx[TTSDeviceName]..'&nvalue=0&svalue='..url_encode(txt)} +end + +-- récupère les infos json du périphérique +-- usage +-- local lampe = jsonInfos('ma lampe') +-- print(lampe.Name) +-- print(lampe.Status) +-- etc.. +function jsonInfos(device) + local rid = assert(io.popen(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..'/json.htm?type=devices&rid='..otherdevices_idx[device]..'"')) + local list = rid:read('*all') + rid:close() + return json:decode(list).result[1] +end + +-- parcours la table dans l'ordre +function spairs(t) + local keys = {} + for k in pairs(t) do keys[#keys+1] = k end + table.sort(keys) + local i = 0 + return function() + i = i + 1 + if keys[i] then + return keys[i], t[keys[i]] + end + end +end + +-- Renverse une table +function ReverseTable(t) + local reversedTable = {} + local itemCount = #t + for k, v in ipairs(t) do + reversedTable[itemCount + 1 - k] = v + end + return reversedTable +end + +-- affiche le contenu d'une table +--[[ + + Author: Julio Manuel Fernandez-Diaz + Date: January 12, 2007 + (For Lua 5.1) + + Modified slightly by RiciLake to avoid the unnecessary table traversal in tablecount() + + Formats tables with cycles recursively to any depth. + The output is returned as a string. + References to other tables are shown as values. + Self references are indicated. + + The string returned is "Lua code", which can be procesed + (in the case in which indent is composed by spaces or "--"). + Userdata and function keys and values are shown as strings, + which logically are exactly not equivalent to the original code. + + This routine can serve for pretty formating tables with + proper indentations, apart from printing them: + + print(table_show(t, "t")) -- a typical use + + Heavily based on "Saving tables with cycles", PIL2, p. 113. + + Arguments: + t is the table. + name is the name of the table (optional) + indent is a first indentation (optional). +]] +function table_show(t, name, indent) + local cart -- a container + local autoref -- for self references + + --[[ counts the number of elements in a table + local function tablecount(t) + local n = 0 + for _, _ in pairs(t) do n = n+1 end + return n + end + ]] + -- (RiciLake) returns true if the table is empty + local function isemptytable(t) return next(t) == nil end + + local function basicSerialize (o) + local so = tostring(o) + if type(o) == "function" then + local info = debug.getinfo(o, "S") + -- info.name is nil because o is not a calling level + if info.what == "C" then + return string.format("%q", so .. ", C function") + else + -- the information is defined through lines + return string.format("%q", so .. ", defined in (" .. + info.linedefined .. "-" .. info.lastlinedefined .. + ")" .. info.source) + end + elseif type(o) == "number" or type(o) == "boolean" then + return so + else + return string.format("%q", so) + end + end + + local function addtocart (value, name, indent, saved, field) + indent = indent or "" + saved = saved or {} + field = field or name + + cart = cart .. indent .. field + + if type(value) ~= "table" then + cart = cart .. " = " .. basicSerialize(value) .. ";\n" + else + if saved[value] then + cart = cart .. " = {}; -- " .. saved[value] + .. " (self reference)\n" + autoref = autoref .. name .. " = " .. saved[value] .. ";\n" + else + saved[value] = name + --if tablecount(value) == 0 then + if isemptytable(value) then + cart = cart .. " = {};\n" + else + cart = cart .. " = {\n" + for k, v in pairs(value) do + k = basicSerialize(k) + local fname = string.format("%s[%s]", name, k) + field = string.format("[%s]", k) + -- three spaces between levels + addtocart(v, fname, indent .. " ", saved, field) + end + cart = cart .. indent .. "};\n" + end + end + end + end + + name = name or "table" + if type(t) ~= "table" then + return name .. " = " .. basicSerialize(t) + end + cart, autoref = "", "" + addtocart(t, name, indent) + return cart .. autoref +end + +-- retourne la table des derniers log (première ligne = dernier log) +function lastLogEntry() + local rid = assert(io.popen(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..'/json.htm?type=command¶m=getlog"')) + local list = rid:read('*all') + rid:close() + local tableau = json:decode(list).result + return ReverseTable(tableau) +end + +-- notification pushbullet +-- usage: +-- pushbullet('test','ceci est un message test') +function pushbullet(title,body) + local settings = assert(io.popen(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..'/json.htm?type=settings"')) + local list = settings:read('*all') + settings:close() + local pushbullet_key = json:decode(list).PushbulletAPI + os.execute(curl..'-H \'Access-Token:'..pushbullet_key..'\' -H \'Content-Type:application/json\' --data-binary \'{"title":"'..title..'","body":"'..body..'","type":"note"}\' -X POST "https://api.pushbullet.com/v2/pushes"') +end + +-- switch On a device and set level if dimmmable +function switchOn(device,level) + local api = '/json.htm?type=command¶m=switchlight' + local idx = '&idx='..otherdevices_idx[device] + local cmd + if level ~= nil then + cmd = '&switchcmd=Set%20Level&level='..level + else + cmd = '&switchcmd=On' + end + local passcode = '&passcode='..domoticzPASSCODE + api = api..idx..cmd..passcode + os.execute(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..api..'" &') +end + +-- switch On a devive for x secondes +function switchOnFor(device, secs) + switchOn(device) + commandArray[#commandArray+1] = {[device] = "Off AFTER "..secs} +end + +-- switch Off a device +function switchOff(device) + local api = '/json.htm?type=command¶m=switchlight' + local idx = '&idx='..otherdevices_idx[device] + local cmd = '&switchcmd=Off' + local passcode = '&passcode='..domoticzPASSCODE + api = api..idx..cmd..passcode + os.execute(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..api..'" &') +end + +-- Toggle a device +function switch(device) + local api = '/json.htm?type=command¶m=switchlight' + local idx = '&idx='..otherdevices_idx[device] + local cmd = '&switchcmd=Toggle' + local passcode = '&passcode='..domoticzPASSCODE + api = api..idx..cmd..passcode + os.execute(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..api..'" &') +end + +-- switch On a group or scene +function groupOn(device) + local api = '/json.htm?type=command¶m=switchscene' + local idx = '&idx='..otherdevices_scenesgroups_idx[device] + local cmd = '&switchcmd=On' + local passcode = '&passcode='..domoticzPASSCODE + api = api..idx..cmd..passcode + os.execute(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..api..'" &') +end + +-- switch Off a group +function groupOff(device) + local api = '/json.htm?type=command¶m=switchscene' + local idx = '&idx='..otherdevices_scenesgroups_idx[device] + local cmd = '&switchcmd=Off' + local passcode = '&passcode='..domoticzPASSCODE + api = api..idx..cmd..passcode + os.execute(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..api..'" &') +end + +-- Set switch to Stop +function switchStop(device) + local api = '/json.htm?type=command¶m=switchlight' + local idx = '&idx='..otherdevices_idx[device] + local cmd = '&switchcmd=Stop' + local passcode = '&passcode='..domoticzPASSCODE + api = api..idx..cmd..passcode + os.execute(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..api..'" &') +end + +-- Setup a color & brightness of an RGB(W) light +-- API : https://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s#Set_an_RGB.28W.29_light_to_a_certain_color_and_brightness +function setColorAndBrightness(device, color, brightness) + local api = '/json.htm?type=command¶m=setcolbrightnessvalue' + local idx = '&idx='..otherdevices_idx[device] + --local color = '&hue='..color + local color = '&hex='..color + local brightness = '&brightness='..brightness + local iswhite = '&iswhite=false' + local passcode = '&passcode='..domoticzPASSCODE + api = api..idx..color..brightness..iswhite..passcode + os.execute(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..api..'" &') +end + +function KelvinToRGB(temp) + -- http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/ + temp = temp/100 + local red, green, blue + --Calculate Red: + if temp <= 66 then + red = 255 + else + red = constrain(round(329.698727446 * ((temp - 60) ^ -0.1332047592)),0,255) + end + --Calculate Green: + if temp <= 66 then + green = constrain(round(99.4708025861 * math.log(temp) - 161.1195681661),0,255) + else + green = constrain(round(288.1221695283 * ((temp - 60) ^ -0.0755148492)),0,255) + end + --Calculate Blue: + if temp >= 66 then + blue = 255 + else + if temp <= 19 then + blue = 0 + else + blue = constrain(round(138.5177312231 * math.log(temp - 10) - 305.0447927307),0,255) + end + end + return {red,green,blue} +end + +function RGBToHex(rgb) + -- https://gist.github.com/marceloCodget/3862929 + local hexadecimal = '' + for key, value in pairs(rgb) do + local hex = '' + while(value > 0)do + local index = math.fmod(value, 16) + 1 + value = math.floor(value / 16) + hex = string.sub('0123456789ABCDEF', index, index) .. hex + end + if(string.len(hex) == 0)then + hex = '00' + elseif(string.len(hex) == 1)then + hex = '0' .. hex + end + hexadecimal = hexadecimal .. hex + end + return hexadecimal +end + +function suntimeToKelvin() + -- http://easydomoticz.com/forum/viewtopic.php?f=10&t=6160 + local mini = 1900 + local maxi = 6600 + local delta = maxi - mini + local wakeup = 60*timeofday['SunriseInMinutes'] + local goodnight = 60*timeofday['SunsetInMinutes'] + local periode = goodnight - wakeup + local offset = wakeup-periode/2 + local color = mini + local time = os.date("*t") + local now = 60*(time.hour*60 + time.min) + if now >= wakeup and now < goodnight then + color = math.floor((maxi-delta/2)+(delta/2)*math.cos((now-offset)*2*math.pi/periode)+0.5) + end + return color +end + +-- régulation chauffage (PID) +--[[ + + usage: + + local pid={} + pid['debug'] = true -- true pour voir les logs dans la console log Dz ou false pour ne pas les voir + pid['zone'] = 'salon' -- nom de la zone pour affichage dans les logs et ditinction de variables + pid['sonde'] = 'salon' -- Nom de la sonde de température + pid['OnOff'] = 'chauffage' -- Nom de l'interrupteur virtuel de mise en route (hivers/été) + pid['thermostat'] = 'th_salon' -- consigne ou 'nom' de l'interrupteur virtuel de thermostat + -- actionneur + pid['radiateur'] = 'radiateur salon' -- Nom de l'interrupteur de chauffage + pid['invert'] = false -- si On et Off doivent être inversé ou non + + -- PID -- + pid['Kp'] = 70 -- Coefficient proportionnel + pid['Ki'] = 8 -- Coefficient intégrateur + pid['Kd'] = 3 -- Coefficient dérivateur + + pid['cycle'] = 15 -- temps en minute d'un cycle PID + pid['secu'] = 60 -- temps mini en seconde entre 2 ordres opposés + + commandArray = {} + compute(pid) + return commandArray + +]] +function compute(pid) + local init = 0 + + -- récupération température + local temp = getTemp(pid['sonde']) + -- récupération température ext + local temp_ext = nil + if pid['sonde_ext'] ~= '' and pid['sonde_ext'] ~= nil then + temp_ext = getTemp(pid['sonde_ext']) + end + + -- création variable : 4 dernières températures + if (uservariables['PID_temps_'..pid['zone']] == nil ) then + creaVar('PID_temps_'..pid['zone'],string.rep(temp..';',3)..temp) + init = 1 + end + -- création variable : intégrale + if (uservariables['PID_integrale_'..pid['zone']] == nil ) then + creaVar('PID_integrale_'..pid['zone'],'0') + init = 1 + end + + if init == 1 then + log('PID '..pid['zone']..' initialisation..',pid['debug']) + do return end + end + + -- définition des variables locales + local moy_erreur = 0 + local n = 1 + local somme_erreurs = 0 + local heatTime + local marche + local arret + local tmp = {} + + -- définition des commandes marche/arrêt + if pid['invert'] then + marche = 'Off' ; arret = 'On' + else + marche = 'On' ; arret = 'Off' + end + + -- à chaque cycle + if ( time.min%pid['cycle'] == 0 ) then + + -- maj des 4 dernières temps + local temps = string.match(uservariables['PID_temps_'..pid['zone']],";([^%s]+)")..";"..temp + commandArray[#commandArray+1] = {['Variable:PID_temps_'..pid['zone']] = temps} + + -- si l'on veut chauffer + if ( otherdevices[pid['OnOff']] == 'On' ) then + + -- récupération de la consigne + local consigne = tonumber(otherdevices_svalues[pid['thermostat']]) or pid['thermostat'] + -- calcul de l'erreur + local erreur = consigne-temp + -- calcul intégrale auto consumée et moyenne erreur glissante + temps:gsub("([+-]?%d+%.*%d*)",function(t) + tmp[n] = tonumber(t) + err = tonumber(consigne-t) + somme_erreurs = somme_erreurs+err + moy_erreur = moy_erreur+err*n^3 + n = n+1 + end) + + somme_erreurs = round(constrain(somme_erreurs,0,255),1) + moy_erreur = round(moy_erreur/100,2) + + -- calcul de la dérivée (régression linéaire - méthode des moindres carrés) + local delta_erreurs = round((4*(4*tmp[1]+3*tmp[2]+2*tmp[3]+tmp[4])-10*(tmp[1]+tmp[2]+tmp[3]+tmp[4]))/20,2) + + -- aux abords de la consigne, passage au second systême integrale + if somme_erreurs < 2 then + somme_erreurs = tonumber(uservariables['PID_integrale_'..pid['zone']]) + -- re calcule intégrale si hors hysteresis + -- à moins d'un dixièmes de degré d'écart avec la consigne + -- le ratrapage est considéré OK, l'intégrale n'est pas recalculée + if math.abs(erreur) > 0.11 then + -- calcule intégrale + somme_erreurs = round(constrain(somme_erreurs+erreur/2,0,5),2) + -- maj + commandArray[#commandArray+1] = {['Variable:PID_integrale_'..pid['zone']] = tostring(somme_erreurs)} + end + end + + -- boucle ouverte, + -- modification dynamique des paramètres de régulation suivant température extérieure + local Kb = 0 + if temp_ext ~= nil then + Kb = pid['Kb'] * (consigne - temp_ext - pid['ref']) / 100 + end + pid['Kp'] = round(pid['Kp'] + pid['Kp'] * Kb) + pid['Ki'] = round(pid['Ki'] + pid['Ki'] * Kb) + pid['Kd'] = round(pid['Kd'] + pid['Kd'] * Kb) + + -- calcul pid + local P = round(pid['Kp']*moy_erreur,2) + local I = round(pid['Ki']*somme_erreurs,2) + local D = round(pid['Kd']*delta_erreurs,2) + + -- calcul de la commande en % + local commande = round(constrain(P+I+D,0,100)) + + -- calcul du temps de fonctionnement + if commande == 100 then + -- débordement de 20s pour ne pas couper avant recalcule + heatTime = (pid['cycle']*60)+20 + elseif commande > 0 then + -- secu mini maxi + heatTime = round(constrain(commande*pid['cycle']*0.6,pid['secu'],(pid['cycle']*60)-pid['secu'])) + elseif commande == 0 then + -- coupure retardée + heatTime = constrain(pid['secu']-lastSeen(pid['radiateur']),0,pid['secu']) + end + + -- AFTER n'aime pas 1 ou 2.. + if heatTime == 1 or heatTime == 2 then + heatTime = 0 + end + + -- action sur l'élément chauffant + if heatTime > 0 then + commandArray[#commandArray+1] = {[pid['radiateur']] = marche} + commandArray[#commandArray+1] = {[pid['radiateur']] = arret..' AFTER '..heatTime} + else + commandArray[#commandArray+1] = {[pid['radiateur']]=arret} + end + + -- journalisation + if pid['debug'] then + log('PID zone: '..string.upper(pid['zone'])) + if temp_ext ~= nil then + log('temperature ext: '..temp_ext..'°C') + end + log('température int: '..temp..'°C pour '..consigne..'°C souhaité') + log('Kp: '..pid['Kp']) + log('Ki: '..pid['Ki']) + log('Kd: '..pid['Kd']) + log('erreur: '..moy_erreur) + log('somme erreurs: '..somme_erreurs) + log('delta erreurs: '..delta_erreurs) + log('P: '..P) + log('I: '..I) + log('D: '..D) + log('cycle: '..pid['cycle']..'min (sécu: '..pid['secu']..'s)') + -- avertissement si secu dépasse 1/4 du cycle + if ((100*pid['secu'])/(60*pid['cycle'])>25) then + warn('sécu trop importante, ralonger durée de cycle..') + end + log('commande: '..commande..'% ('..string.sub(os.date("!%X",heatTime),4,8):gsub("%:", "\'")..'\")') + log('') + end + + -- maj sonde virtuelle + --commandArray[#commandArray+1] = {['UpdateDevice'] = otherdevices_idx[pid['sonde']..'_pid']..'|0|'..temp..';'..commande..';0'} + + end + + end + -- toutes les 15 minutes, si on ne veut pas chauffer + if ( time.min%15 == 0 and otherdevices[pid['OnOff']] == 'Off' ) then + + -- arrêt chauffage (renvoi commande systematique par sécurité) + commandArray[#commandArray+1] = {[pid['radiateur']] = arret..' AFTER '..constrain(pid['secu']-lastSeen(pid['radiateur']),3,pid['secu'])} + + -- maj sonde virtuelle + --commandArray[#commandArray+1] = {['UpdateDevice'] = otherdevices_idx[pid['sonde']..'_pid']..'|0|'..temp..';0;0'} + end + +end + +-- détermination automatique des paramètres de régulation PID +function autotune(pid) + + -- http://brettbeauregard.com/blog/2012/01/arduino-pid-autotune-library/ + + if devicechanged[pid['sonde']] then + + -- définition des commandes marche/arrêt + if pid['invert'] then + marche = 'Off' ; arret = 'On' + else + marche = 'On' ; arret = 'Off' + end + + -- récupération température + local temp = getTemp(pid['sonde']) + -- récupération consigne + local consigne = tonumber(otherdevices_svalues[pid['thermostat']]) or pid['thermostat'] + + -- hysteresis + if temp > consigne then + commandArray[#commandArray+1] = {[pid['radiateur']] = arret} + elseif temp < consigne then + commandArray[#commandArray+1] = {[pid['radiateur']] = marche} + end + + -- timestamp + local now = os.time() + + -- save all temps + logToFile(pid['zone']..'_temps',now..';'..temp) + + local max1 = consigne + local max2 = consigne + local mini = consigne + local max1_ts = now + local max2_ts = now + local mini_ts = now + local init = 0 + + -- recherche des valeurs mini/maxi + for _,v in spairs(ReverseTable(lines_from(pid['zone']..'_temps'))) do + t = tonumber(string.match(v,";([^%s]+)")) + ts = tonumber(string.match(v,"([^%s]+);")) + if t < mini and init == 0 then + init = 1 + elseif t > max2 and (init == 1 or init == 2) then + init = 2 + max2 = t + max2_ts = ts + elseif t < mini and (init == 2 or init == 3) then + init = 3 + mini = t + mini_ts = ts + elseif t > max1 and (init == 3 or init == 4) then + init = 4 + max1 = t + max1_ts = ts + elseif t <= consigne and init == 4 then + init = 5 + break + end + end + + -- autotune + local Pu = round(os.difftime(max2_ts, max1_ts) / 60) + local A = tonumber(max1 - mini) + local Ku = round(200 / (A * math.pi)) + local Kp = round(0.6 * Ku) + local Ki = round(1.2 * Ku / Pu * pid['cycle']) + local Kd = round(0.075 * Ku * Pu / pid['cycle']) + + -- journalisation + log('PID autotune '..string.upper(pid['zone'])) + if init == 5 then + log('max1: '..max1..' a '..os.date('%H:%M', max1_ts),pid['debug']) + log('mini: '..mini..' a '..os.date('%H:%M', mini_ts),pid['debug']) + log('max2: '..max2..' a '..os.date('%H:%M', max2_ts),pid['debug']) + log('Pu:'..Pu,pid['debug']) + log('A:'..A,pid['debug']) + log('Ku:'..Ku,pid['debug']) + log('Kp:'..Kp..' Ki:'..Ki..' Kd:'..Kd) + else + log('mesures en cours..') + end + + end +end + +function humiditeAbsolue(T, rh) + -- https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/ + + -- Formula for calculating absolute humidity + -- In the formula below, temperature (T) is expressed in degrees Celsius, relative humidity (rh) is expressed in %, and e is the base of natural logarithms 2.71828 [raised to the power of the contents of the square brackets]: + -- Absolute Humidity (grams/m3) = 6.112 × e^[(17.67 × T)/(T+243.5)] × rh × 18.02 + --(273.15+T) × 100 × 0.08314 + -- which simplifies to + -- Absolute Humidity (grams/m3) = 6.112 × e^[(17.67 × T)/(T+243.5)] × rh × 2.1674 / (273.15+T) + -- This formula is accurate to within 0.1% over the temperature range –30°C to +35°C + + local absoluteH = 6.112 * math.pow(2.71828, (17.67 * T) / (T + 243.5)) * rh * 2.1674 / (273.15+T) + + print("Humidité absolute T="..tostring(T)..' H='..tostring(rh)..' '..tostring(absoluteH)) + + return absoluteH +end diff --git a/lua/forecast.lua b/lua/forecast.lua new file mode 100644 index 0000000..5e4e25c --- /dev/null +++ b/lua/forecast.lua @@ -0,0 +1,145 @@ +local cjson = require "cjson" + +-- Exemple de JSON +local json_str = [[ +{ + "cod": "200", + "message": 0, + "cnt": 40, + "list": [ + { + "dt": 1718312400, + "main": { + "temp": 12.84, + "feels_like": 12.61, + "temp_min": 12.84, + "temp_max": 13.87, + "pressure": 1010, + "sea_level": 1010, + "grnd_level": 1004, + "humidity": 93, + "temp_kf": -1.03 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10n" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 6.07, + "deg": 200, + "gust": 11.82 + }, + "visibility": 10000, + "pop": 1, + "rain": { + "3h": 1.17 + }, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-06-13 21:00:00" + }, + { + "dt": 1718323200, + "main": { + "temp": 14.27, + "feels_like": 14.21, + "temp_min": 14.27, + "temp_max": 15.25, + "pressure": 1009, + "sea_level": 1009, + "grnd_level": 1002, + "humidity": 94, + "temp_kf": -0.98 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10n" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 5.33, + "deg": 255, + "gust": 9.41 + }, + "visibility": 10000, + "pop": 1, + "rain": { + "3h": 0.18 + }, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-06-14 00:00:00" + }, + { + "dt": 1718334000, + "main": { + "temp": 13.46, + "feels_like": 13.37, + "temp_min": 13.46, + "temp_max": 13.46, + "pressure": 1008, + "sea_level": 1008, + "grnd_level": 1002, + "humidity": 96, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "légère pluie", + "icon": "10n" + } + ], + "clouds": { + "all": 77 + }, + "wind": { + "speed": 3.98, + "deg": 240, + "gust": 10.97 + }, + "visibility": 10000, + "pop": 0.2, + "rain": { + "3h": 0.1 + }, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-06-14 03:00:00" + }, + ... + ] +} +]] + +-- Décoder le JSON +local data = cjson.decode(json_str) + +-- Extraire les 6 premières valeurs du champ "all" +local cloud_values = {} +for i = 1, math.min(6, #data.list) do + table.insert(cloud_values, data.list[i].clouds.all) +end + +-- Afficher les valeurs extraites +for i, value in ipairs(cloud_values) do + print("Cloud coverage for point " .. i .. ": " .. value) +end + diff --git a/lua/functions.lua b/lua/functions.lua new file mode 100755 index 0000000..206f0e5 --- /dev/null +++ b/lua/functions.lua @@ -0,0 +1,724 @@ +--luasql = require "luasql.sqlite3" + +--http = require "socket.http"; + + +-------------------------------- +------ USER SETTINGS ------ +-------------------------------- + +-- domoticz +domoticzIP = '192.168.1.3' --'127.0.0.1' +domoticzPORT = '81' +domoticzUSER = '' -- nom d'utilisateur +domoticzPSWD = '' -- mot de pass +domoticzPASSCODE = '' -- pour interrupteur protégés +domoticzURL = 'http://'..domoticzIP..':'..domoticzPORT + +-- Ne fonctionne plus +--require "luasql.sqlite3" +--package.preload['luasql.sqlite3'] + +delai = 300 -- delai avant renvoi consigne +maxVariation = 0.15 +radiateurs = {'RadiateurManon','RadiateurTheo','RadiateurChambre','RadiateurBureau','RadiateurCuisine','RadiateurMilieu','RadiateurCheminee', 'RadiateurPorteSalon'} + +function updatenum(dev, value1) + print("NRJ updatenum "..dev.." "..tostring(value1)) + --local cmd = string.format("%d|0|%d", otherdevices_idx[dev], math.floor(value1)) + local cmd = tostring(otherdevices_idx[dev]).."|0|"..tostring(round(value1, 3)) + + table.insert (commandArray, { ['UpdateDevice'] = cmd } ) +end +function ternary ( cond , T , F ) + if cond then return T else return F end +end +function isempty(s) + return s == nil or s == '' +end + +-- Retourne le jour de la semaine (lundi...dimanche) +josdGetJourSemaineTab={[0]="dimanche",[1]="lundi",[2]="mardi",[3]="mercredi",[4]="jeudi",[5]="vendredi",[6]="samedi"} +function josdGetJourSemaine() + return josdGetJourSemaineTab[tonumber(os.date("%w"))] +end + +-- Retourne le jour de Pâques au format epoch +-- annee : année (Integer) dont on désire connaître le jour de Pâques (ex : 2014) +-- La fonction n'effectue le calcul que si l'année a changée depuis son dernier appel +josdGetJourPaquesAnnee=0 -- Variable globale (année du dernier calcul) pour ne pas recalculer le jour de Pâques à chaque appel +josdGetJourPaquesEpochPaque=0 -- Variable globale (jour de Pâques au format epoch) pour ne pas recalculer le jour de Pâques à chaque appel +function josdGetJourPaques(annee) + if(josdGetJourPaquesAnnee~=annee or josdGetJourPaquesEpochPaque==0) then + local a=math.floor(annee/100) + local b=math.fmod(annee,100) + local c=math.floor((3*(a+25))/4) + local d=math.fmod((3*(a+25)),4) + local e=math.floor((8*(a+11))/25) + local f=math.fmod((5*a+b),19) + local g=math.fmod((19*f+c-e),30) + local h=math.floor((f+11*g)/319) + local j=math.floor((60*(5-d)+b)/4) + local k=math.fmod((60*(5-d)+b),4) + local m=math.fmod((2*j-k-g+h),7) + local n=math.floor((g-h+m+114)/31) + local p=math.fmod((g-h+m+114),31) + local jour=p+1 + local mois=n + josdGetJourPaquesAnnee=annee + josdGetJourPaquesEpochPaque=os.time{year=annee,month=mois,day=jour,hour=12,min=0} + end + return josdGetJourPaquesEpochPaque +end + + +-- Retourne true si le jour courant est un jour férié +-- Le calcul des jours férié n'est fait qu'un fois par an (ou si la Vera reboot) +josdJourFerieAnnee=0 -- Variable globale (année du dernier calcul) pour ne pas recalculer le tableau à chaque appel +josdJourFerieTab = {} -- Variable globale (tableau des jours fériés) pour ne pas recalculer le tableau à chaque appel +function josdJourFerie() + local today=os.date("%m-%d") + local annee=tonumber(os.date("%Y")) + if(annee~=josdJourFerieAnnee) then + josdJourFerieAnnee=annee + -- Dates fixes + josdJourFerieTab["01-01"] = true -- 1er janvier + josdJourFerieTab["05-01"] = true -- Fête du travail + josdJourFerieTab["05-08"] = true -- Victoire des alliés + josdJourFerieTab["07-14"] = true -- Fête nationale + josdJourFerieTab["08-15"] = true -- Assomption + josdJourFerieTab["11-01"] = true -- Toussaint + josdJourFerieTab["11-11"] = true -- Armistice + josdJourFerieTab["12-25"] = true -- Noël + -- Dates variables + local epochPaques=josdGetJourPaques(annee) + josdJourFerieTab[os.date("%m-%d",epochPaques)] = true -- Pâques + josdJourFerieTab[os.date("%m-%d",epochPaques+24*60*60)] = true -- Lundi de Pâques = Pâques + 1 jour + josdJourFerieTab[os.date("%m-%d",epochPaques+24*60*60*39)] = true -- Ascension = Pâques + 39 jours + josdJourFerieTab[os.date("%m-%d",epochPaques+24*60*60*49)] = true -- Pentecôte = Ascension + 49 jours + end + return josdJourFerieTab[today] -- (nldr : Both nil and false make a condition false) +end +-- Retourne true si le jour courant est un jour chômé (passé à la maison) +-- Le calcul effectif n'est fait qu'une fois par jour (ou si la Vera reboot) +josdJourChomeToday="NULL" -- Variable globale (date du dernier calcul) pour ne pas recalculer le résultat à chaque appel +josdJourChomeReturn=false -- Variable globale (résulat du dernier calcul) pour ne pas recalculer le résultat à chaque appel +function josdJourChome() + local today=os.date("%Y-%m-%d") + if(today~=josdJourChomeToday) then -- Faut-il refaire le calcul ? + local jour=josdGetJourSemaine() + josdJourChomeToday=today + josdJourChomeReturn=(jour=="samedi" or jour=="dimanche" --or jour=="mercredi" + or josdJourFerie()) + -- or josdJourVacances()) + end + return josdJourChomeReturn +end +-- ------------------------------------------------------------------------------ +-- transforme une heure en minute +-- ------------------------------------------------------------------------------ +function heureEnMinute(t1) + + s1 = split(t1, ":") + h1 = tonumber(s1[1]) + m1 = tonumber(s1[2]) + + return h1 * 60 + m1 + +end + +-- ------------------------------------------------------------------------------ +-- compare 2 heures +-- ------------------------------------------------------------------------------ +function greater(t1, t2) + return greater2(t1, t2, 0) +end +-- ------------------------------- +-- retourne vrai si t1 > t2 + m +-- ------------------------------- +function greater2(t1, t2, m) + + s1 = split(t1, ":") + s2 = split(t2, ":") + + h1 = tonumber(s1[1]) + h2 = tonumber(s2[1]) + m1 = tonumber(s1[2]) + m2 = tonumber(s2[2]) + + if h1 * 60 + m1 > h2 * 60 + m2 + m then return true end + --if h1 == h2 and m1 > m2 then return true end + + return false + +end +-- ------------------------------------------------------------------------------ +-- Function sleep n seconds +-- ------------------------------------------------------------------------------ +function sleep(n) + os.execute("sleep " .. tonumber(n)) +end + +-- ------------------------------------------------------------------------------ +-- Truncate number to nb decimal +-- ------------------------------------------------------------------------------ +function round(num, idp) + local mult = 10^(idp or 0) + return math.floor(num * mult + 0.5) / mult +end + +-- ------------------------------------------------------------------------------ +-- Get the temperature from a device which contains humidity and pressure too +-- ------------------------------------------------------------------------------ +function getTemperatureFromDevice(device) + return tonumber(split(otherdevices_svalues[device],";")[1]) +end +-- ------------------------------------------------------------------------------ +-- Get the humidity from a device which contains temperature and pressure too +-- ------------------------------------------------------------------------------ +function getHumidityFromDevice(device) + return tonumber(split(otherdevices_svalues[device],";")[2]) +end + +-- Test if string is empty or null +function isempty(s) + return s == nil or s == '' +end + +-- ------------------------------------------------------------------------------ +-- Permet de couper une chaine de caracteres avec separateur en plusieurs chaines +-- ------------------------------------------------------------------------------ +function split(str, pat) + local t = {} -- NOTE: use {n = 0} in Lua-5.0 + local fpat = "(.-)" .. pat + local last_end = 1 + local s, e, cap = str:find(fpat, 1) + while s do + if s ~= 1 or cap ~= "" then + table.insert(t,cap) + end + last_end = e+1 + s, e, cap = str:find(fpat, last_end) + end + if last_end <= #str then + cap = str:sub(last_end) + table.insert(t, cap) + end + return t +end + +-- ------------------------------------------------------------------------------ +-- Met à jour un switch si nécessaire (déjà à la bonne position) +-- ------------------------------------------------------------------------------ +function switchIfNeeded( switch, value ) + if switch == "RadiateurGrenier" then + local currentValue = tonumber(otherdevices_svalues["RadiateurGrenier"]) + + if value == "On" then + if (otherdevices[switch] == 'Off') then + switchOn(switch) -- commandArray[switch]=value + end + + switchOnDimmable(switch, currentValue + 1) + else + if currentValue <= 1 then + switchOnDimmable(switch, 0) + else + if (otherdevices[switch] ~= 'Off') then + switchOnDimmable(switch, currentValue - 1) + end + end + end + + print(switch .. ' ' ..value..' current='..currentValue..' '..otherdevices[switch]) + + else + if (otherdevices[switch] == value and not string.match(switch, "Radiateur")) then -- and lastUpdateOfDevice(switch) < 300) then + debug(switch..' already '..value) + else + if value == "On" then + debug(switch..' '..value) + switchOn(switch) -- commandArray[switch]=value + else + switchOff(switch) + debug(switch..' '..value) + end + end + --sleep(1) + end +end + +-- ------------------------------------------------------------------------------ +-- Met à jour un switch si nécessaire (déjà à la bonne position) +-- ------------------------------------------------------------------------------ +function switchLightsIfNeeded( value ) + switchIfNeeded('Lampe_Halogene', value) + sleep(1) + switchIfNeeded('Lampe_Buffet', value) + sleep(1) + switchIfNeeded('Lampe_Tele', value) + sleep(1) + switchIfNeeded('Lampe_Led', value) +end + +-- ------------------------------------------------------------------------------ +-- Function to get result of HTTP request +-- ------------------------------------------------------------------------------ +function os.capture(cmd, raw) + local f = assert(io.popen(cmd, 'r')) + local s = assert(f:read('*a')) + f:close() + if raw then return s end + s = string.gsub(s, '^%s+', '') + s = string.gsub(s, '%s+$', '') + s = string.gsub(s, '[\n\r]+', ' ') + return s +end +-- ------------------------------------------------------------------------------ +-- Function to get the last update of device from now in seconds +-- ------------------------------------------------------------------------------ +function lastUpdateOfDevice(switch) + t1 = os.time() + s = otherdevices_lastupdate[switch] + difference = 0 + if (s == nil) then + debug("Erreur détermination lastUpdate "..switch) + else + -- returns a date time like 2013-07-11 17:23:12 + year = string.sub(s, 1, 4) + month = string.sub(s, 6, 7) + day = string.sub(s, 9, 10) + hour = string.sub(s, 12, 13) + minu = string.sub(s, 15, 16) + seconds = string.sub(s, 18, 19) + + t2 = os.time{year=year, month=month, day=day, hour=hour, min=minu, sec=seconds} + + difference = (os.difftime (t1, t2)) + --debug(switch..tonumber(difference)) + end + + return difference +end +-- --------------------------------------------------- +-- Function debug +-- --------------------------------------------------- +function debug(string) + if otherdevices['Debug'] == 'On' and string ~= nil then + print("DEBUG "..string) + end +end +-- --------------------------------------------------- +-- Switch off radiateur SIC ! +-- --------------------------------------------------- +function switchOffRadiateur(switch) + debug("Radiateur "..switch.." Off.") + if (otherdevices[switch] == 'On' or lastUpdateOfDevice(switch) > delai) then + --commandArray[switch]='Off' + switchOff(switch) + end + --switchIfNeeded(switch, 'Off') -- Inversion pour les radiateurs +end +-- --------------------------------------------------- +-- Switch on radiateur SIC ! +-- --------------------------------------------------- +function switchOnRadiateur(switch) + debug("Radiateur "..switch.." On.") + if (otherdevices[switch] == 'Off' or lastUpdateOfDevice(switch) > delai) then + --commandArray[switch]='On' + switchOn(switch) + end + --switchIfNeeded(switch, 'On') -- Inversion pour les radiateurs +end + +-- --------------------------------------------------- +-- Get a map of switch values +-- --------------------------------------------------- +function getValuesInTab(switch) + tmp = otherdevices_svalues[switch] + + debug('temperature lue pour '..switch..' '..tmp) + tab = split(tmp, ";") + + return tab + end + +-- --------------------------------------------------- +-- Get the last values of a switch (inverse order) +-- --------------------------------------------------- +function getEvolutionFromSwitch(switch) + + env = luasql.sqlite3() + conn = env:connect("/opt/domoticz/domoticz.db") + + cursor = assert(conn:execute("select temperature,date from temperature,DeviceStatus where DeviceStatus.name = '"..switch.."' and devicerowid = DeviceStatus.id order by date desc limit 10")) + row = {} + while cursor:fetch(row) do + debug(table.concat(row, '|')) + end + + cursor:close() + conn:close() + + env:close() +end + +-- --------------------------------------------------- +-- Execute a query from domoticz db and returns rows +-- --------------------------------------------------- +function executeQuery( switch, query) + + q = "/usr/bin/sqlite3 -list /opt/domoticz/domoticz.db '" .. query .. "' 2>&1" + + --debug(q) + + --debug("avant execute"..q) + local rHandle = io.popen( "/usr/bin/sqlite3 -list /opt/domoticz/domoticz.db '" .. query .. "' 2>&1" ) + local aRows = {} ; local aRow = {}; local iRow = 1 ; local iColumn = 1 + + --debug("avant while true") + while true do + local sResultRow = rHandle:read( '*line' ) + if ( sResultRow == nil ) then break end + + debug(sResultRow) + + for sColumn in sResultRow:gmatch( "([^|]+)" ) do + aRow[iColumn] = sColumn + debug(sColumn) + iColumn = iColumn + 1 + end + + aRows[iRow] = aRow + + iRow = iRow + 1 + iColumn = 1 + aRow = {} + end + --debug("Fin while") + local oReturn = { rHandle:close() } + if ( tonumber( oReturn[3] ) ~= 0 ) then -- check return code (0 = ok) + debug( sQuery_, 4 ) + if ( iRow > 1 ) then + debug( aRows[iRow - 1][1], 4 ) + else + debug( 'Error while executing query.', 4 ) + end + return false + else + debug( sQuery_, 1 ) + return true, aRows, iRow - 1 + end + + --debug("Fin execute") +end + +function executeQueryAndGetValues( switch ) + local bSuccess, aRows, iCount = executeQuery( switch ) + if ( bSuccess ) then + if ( iCount > 0 ) then + return table.unpack( aRows[1] ) + else + return nil + end + else + return false + end +end + +-- -------------------------------------------------------- +-- Détermine la variation de température à prendre en compte +-- -------------------------------------------------------- +function getVariation( switch ) + local time = 10 + variation = variationTemp(switch) + debug("Variation 10' ="..tostring(variation)) + if variation == 0 then + time = 20 + variation = variationTemp2(switch, 20) + debug("Variation 20' ="..tostring(variation)) + end + if variation == 0 then + time = 30 + variation = variationTemp2(switch, 30) + debug("Variation 30' ="..tostring(variation)) + end + return variation, time +end + +-- -------------------------------------------------------- +-- calcul la variation de température depuis n * 5 minutes +-- -------------------------------------------------------- +function variationTemp(switch) + return variationTemp2(switch, 10) +end +function variationTemp2(switch, time) + local limit = time / 5 + 1 + + query = 'select temperature,date from temperature,DeviceStatus where DeviceStatus.Name = "'..switch..'" and devicerowid = DeviceStatus.id order by date desc limit '..tostring(limit) + + --debug("Avant query "..tostring(limit).." "..switch) + local bSuccess, aRows, iCount = executeQuery(switch, query) + + --debug("Retour executeQuery"..tostring(bSuccess).." icount="..iCount) + + local firstTemp = 0 + local lastTemp = 0 + if (bSuccess and iCount > 0) then + firstTemp = tonumber(aRows[1][1]) + lastTemp = tonumber(aRows[iCount][1]) + for i = 1, iCount do + local t = tonumber(aRows[i][1]) + --debug("RETOUR Query"..tostring(aRows[i][1])) + end + end + + return firstTemp - lastTemp +end + +-- --------------------------------------------------- +-- calcul la variation de pression depuis ?? minutes +-- Basse pression == < à 1013mbar (pluie) +-- Haute pression == > à 1013mbar (beau temps) +-- Diminution rapide ==> vent et mauvais temps +-- superieur à 1020 ==> beau temps calme +-- Tendance +-- Tendance du baromètre hPa par heure Évolution du temps +-- montée 0,25 à 0,5 venue d'une haute pression (à long terme) +-- montée 1 à 2 moyenne pression (à court terme) +-- descente 0,25 à 0,5 venue d'une basse pression (à long terme) +-- descente 1 à 2 tempête ; en été, orage. +-- Conversion +-- 10^5 Pa = 1 bar = 1000 mbar = 10,2 mCE (mètres de colonne d'eau) = 0,987 atm. +-- --------------------------------------------------- +function variationPressure(switch, time) -- time en minute + local limit = time / 5 + 1 + -- SELECT barometer,date FROM temperature where devicerowid = 94 and date like "2016-02-24 %" order by date desc limit 25 + query = 'select barometer,date from temperature,DeviceStatus where DeviceStatus.Name = "'..switch..'" and devicerowid = DeviceStatus.id order by date desc limit '..tostring(limit) + + local bSuccess, aRows, iCount = executeQuery(switch, query) + + debug("Retour executeQuery"..tostring(bSuccess).." icount="..iCount) + + local firstTemp = 0 + local lastTemp = 0 + if (bSuccess and iCount > 0) then + firstTemp = tonumber(aRows[1][1]) + lastTemp = tonumber(aRows[iCount][1]) + for i = 1, iCount do + local t = tonumber(aRows[i][1]) + debug("RETOUR Query"..tostring(aRows[i][1])) + end + end + + return firstTemp - lastTemp +end + + +-- ----------------- +-- Multiple update +-- ----------------- +function update(idx, value1, value2) + local cmd = string.format("%d|0|%.2f;%.2f", idx, value1, value2) + table.insert (commandArray, { ['UpdateDevice'] = cmd } ) +end +function updateCmd(idx, value1) + local cmd = idx.."|"..value1 + table.insert (commandArray, { ['UpdateDevice'] = cmd } ) +end + +-- PERF + +-- /!\ require Domoticz v3.5776 and after /!\ + +curl = '/usr/bin/curl -m 3 ' -- don't forgot the final space + +domoticzIP = 'localhost' +domoticzPORT = '81' +domoticzURL = 'http://'..domoticzIP..':'..domoticzPORT + +-- switch On a device and set level if dimmmable +function switchOnDimmable(device, level) + print(device..' '..tostring(level)) + os.execute(curl..'"'..domoticzURL..'/json.htm?type=command¶m=switchlight&idx='..otherdevices_idx[device]..'&switchcmd=Set%20Level&level='..level..'" &') +end +function switchOn(device) + if (otherdevices_idx[device] ~= nil) then + os.execute(curl..'"'..domoticzURL..'/json.htm?type=command¶m=switchlight&idx='..otherdevices_idx[device]..'&switchcmd=On" &') + end +end +-- switch On a devive for x seconds +-- non compatible avec le script sendTwice +function switchOnFor(device, secs) + if (otherdevices_idx[device] ~= nil) then + switchOn(device) + commandArray[device] = "Off AFTER "..secs + end +end + +-- switch Off a device +function switchOff(device) + if (otherdevices_idx[device] ~= nil) then + os.execute(curl..'"'..domoticzURL..'/json.htm?type=command¶m=switchlight&idx='..otherdevices_idx[device]..'&switchcmd=Off" &') + end + end + +-- Toggle a device +function switch(device) + if (otherdevices_idx[device] ~= nil) then + os.execute(curl..'"'..domoticzURL..'/json.htm?type=command¶m=switchlight&idx='..otherdevices_idx[device]..'&switchcmd=Toggle" &') + end +end + +-- switch On a group or scene +function groupOn(device) + if (otherdevices_idx[device] ~= nil) then + os.execute(curl..'"'..domoticzURL..'/json.htm?type=command¶m=switchscene&idx='..otherdevices_scenesgroups_idx[device]..'&switchcmd=On" &') + end +end + +-- switch Off a group +function groupOff(device) + if (otherdevices_idx[device] ~= nil) then + os.execute(curl..'"'..domoticzURL..'/json.htm?type=command¶m=switchscene&idx='..otherdevices_scenesgroups_idx[device]..'&switchcmd=Off" &') + end +end + +-- Retourne le nombre de minutes avant la nuit +function whenDark() + local hour = tonumber(os.date("%H")); + local min = tonumber(os.date("%M")); + local now = 60 * hour + min + local sunsetMin = heureEnMinute(uservariables["Couche"]) + + when_dark = sunsetMin - now + print("####### Dark in "..tostring(when_dark)) + + return when_dark + +end + +-- Retourne le nombre de minutes avant le jour +function whenLight() + local hour = tonumber(os.date("%H")); + local min = tonumber(os.date("%M")); + local now = 60 * hour + min + local sunriseMin = heureEnMinute(uservariables["Lever"]) + + when_light = 1440 - (sunriseMin - now) + debug("####### Light in "..tostring(when_light)) + + return when_light + +end + + +function actionSomfy(name, action) + debug(name..' '..action) + local url = "mosquitto_pub -h www.maqiatto.com -u jerome.delacotte@gmail.com -P setaou -I clientId-9FG7vBimhk -t jerome.delacotte@gmail.com/"..name.."/volet -m "..action + debug(url) + os.execute(url) +end + +-- update an existing variable +function updateVar(name,value) + local api = '/json.htm?type=command¶m=updateuservariable' + local name = '&vname='..url_encode(name) + local vtype = '&vtype=2' + local value = '&vvalue='..url_encode(value) + api = api..name..vtype..value + url = curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..api..'" &' + debug(url) + os.execute(url) +end +function url_encode(str) + if (str) then + str = string.gsub (str, "\n", "\r\n") + str = string.gsub (str, "([^%w %-%_%.%~])", + function (c) return string.format ("%%%02X", string.byte(c)) end) + str = string.gsub (str, " ", "+") + end + return str +end + +-- recursive search value in table +function searchValueInTable(value, tbl) + for k, v in pairs(tbl) do + if v == value then + return k -- Retourne la clé si la valeur est trouvée + elseif type(v) == "table" then + local result = searchValueInTable(value, v) -- Appel récursif si la valeur est un tableau + if result then + return k .. "." .. result -- Retourne la clé trouvée concaténée avec la clé actuelle + end + end + end + return nil -- Retourne nil si la valeur n'est pas trouvée +end + +-- Recursive search key in array +function searchKeyInTable(key, tbl) + for k, v in pairs(tbl) do + if k == key then + return v + elseif type(v) == "table" then + local result = searchKeyInTable(key, v) + if result then + return result + end + end + end + + return nil +end + +function printTableAsTree(tbl, indent) + indent = indent or "" + for key, value in pairs(tbl) do + if type(value) == "table" then + print(indent .. tostring(key) .. ":") + printTableAsTree(value, indent .. "___") + else + print(indent .. tostring(key) .. ": " .. tostring(value)) + end + end +end + +function sendNotification(message) + commandArray['SendNotification'] = message +end + +function getJSONContent(url) + local cmd = 'curl -s --connect-timeout 2 -m 5 "'..url..'"' + --local cmd = 'curl "'..url..'"' + local jsonContent = os.capture(cmd, true) + return jsonContent +end + +function decodeJSON(jsonContent) + json = (loadfile "/opt/domoticz/scripts/lua/JSON.lua")() + return json:decode(jsonContent) +end + +function updateDeviceValue(deviceId, svalue) + local url = domoticzURL..'/json.htm?type=command¶m=udevice&idx='..deviceId..'&svalue='..svalue + print(url) + result = os.execute(curl..'"'..url..'" &') + print(result) +end + +function getExternalTempRef(device_temp) + local val + local val2 + val, val2 = otherdevices_svalues[device_temp]:match("([^;]+);([^;]+)") + print("Volets "..device_temp.." "..otherdevices["Exterieur_Cellier"].." "..val.. + otherdevices['VoletCuisine'].." "..otherdevices['VoletSalonTele'].." "..otherdevices['VoletPorteSalon']) + + return tonumber(val) +end + +function convertirAngle(angle) + local pointsCardinaux = { "N", "NE", "E", "SE", "S", "SW", "W", "NW", "N" } + local index = math.floor(((angle + 22.5) % 360) / 45) + 1 + return pointsCardinaux[index] +end diff --git a/lua/iphone.luaTMP b/lua/iphone.luaTMP new file mode 100755 index 0000000..06a0b42 --- /dev/null +++ b/lua/iphone.luaTMP @@ -0,0 +1,135 @@ +-- ============================== +-- Cherche la position iphone sur icloud +-- ============================== + +-- Variables + +-- 1) User et mot de passe icloud +username = "votre.login@icloud.com" +password = "votre mot de passe icloud" + +-- 2) Pour chaque iPhone déclaré : associer le nom du device de présence +devices = { + ["iPhone de Georges-David"] = "Presence GD" + -- , ["iPhone de Jean-Michel"] = "Présence JM" + -- , ["iPhone de Pierre-André"] = "Présence PA" +} + +-- 3) Pour chaque iPhone déclaré : associer adresse IP et le nom du device de présence +ips= { + ["192.168.0.20"] = "moi" + -- , ["xxx.xxx.xxx"] = "Présence JM" + -- , ["xxx.xxx.xxx"] = "Présence PA" +} + +-- 4) Position de la maison, "lat, long" as given by google map +coordonneesGoogleDeLaMaison="47.726695, -2.131950" + --(43.693982097361, 0.00010012119960745) +-- 5) Périmètre de considération de la maison +-- NB : 0.001 = 0.111 kilometres soit 111 metres +skew = 0.001 + +-- ============================== +commandArray = {} + +print('Script v01 script_time_localisation.lua') +function debug(m) + print("........ localisation "..m) +end + +function Allumer(item) + if otherdevices[item] ~= 'On' then commandArray[item] = 'On' end +end + +function Eteindre(item) + if otherdevices[item] ~= 'Off' then commandArray[item] = 'Off' end +end + + +-- Time to run? +time = os.date("*t") + +-- toutes les minutes, on allume si l'adresse IP répond au ping +-- ce mécanisme n'est pas utilisé pour éteindre : contrairement +-- à Android, l'IPhone éteint le wifi quand il est en veille. +for ip, devicePresence in pairs(ips) do + -- local status = os.execute("ping -W 1 -q -c 1 "..ip) !! pas bon, comme as dit papoo + local status = os.execute("ping -W 1 -q -c 4 "..ip) + if status == true then + Allumer(devicePresence) + end +end + +-- On vérifie toute les 10 minutes +if time.min % 10 == 2 then + --- Faire un premier appel pour recherche la position + urlCloud1 = ("curl -s -X POST -D - -o /dev/null -L -u '" .. username .. ":" .. password .. "' " + .. "-H 'Content-Type: application/json; charset=utf-8' " + .. "-H 'X-Apple-Find-Api-Ver: 2.0' " + .. "-H 'X-Apple-Authscheme: UserIdGuest' " + .. "-H 'X-Apple-Realm-Support: 1.0' " + .. "-H 'User-agent: Find iPhone/1.3 MeKit (iPad: iPhone OS/4.2.1)' " + .. "-H 'X-Client-Name: iPad' " + .. "-H 'X-Client-UUID: 0cf3dc501ff812adb0b202baed4f37274b210853' " + .. "-H 'Accept-Language: en-us' " + .. "-H 'Connection: keep-alive' https://fmipmobile.icloud.com/fmipservice/device/" + .. username .."/initClient") + -- debug("urlCloud1="..urlCloud1) + local handle = io.popen(urlCloud1) + local result = handle:read("*all") + handle:close() + + -- Récupération de la position dans le resultat de la premiere URL + stageServer = string.match(result, "X%-Apple%-MMe%-Host%:%s(.*%.icloud%.com)") + + -- Faire la deuxième url en cherchant le nom du tel / ipad ou autre avec jq + urlCloud2 = ("curl -s -X POST -L -u '" .. username .. ":" .. password .. "' " + .. "-H 'Content-Type: application/json; charset=utf-8' " + .. "-H 'X-Apple-Find-Api-Ver: 2.0' " + .. "-H 'X-Apple-Authscheme: UserIdGuest' " + .. "-H 'X-Apple-Realm-Support: 1.0' " + .. "-H 'User-agent: Find iPhone/1.3 MeKit (iPad: iPhone OS/4.2.1)' " + .. "-H 'X-Client-Name: iPad' -H 'X-Client-UUID: 0cf3dc501ff812adb0b202baed4f37274b210853' " + .. "-H 'Accept-Language: en-us' " + .. "-H 'Connection: keep-alive' " + .. "https://" .. stageServer .. "/fmipservice/device/" .. username .."/initClient ") + + -- debug("urlCloud2="..urlCloud2) + local handle = io.popen(urlCloud2) + local result = handle:read("*all") + + json = (loadfile "/home/pi/domoticz/scripts/lua/JSON.lua")() + local jsonPosition = json:decode(result) + handle:close() + + latMaison, lonMaison = string.match(coordonneesGoogleDeLaMaison, "(%d+.%d+), (%d+.%d+)") + + for i, iPhone in ipairs(jsonPosition.content) do + devicePresence=devices[iPhone.name] + debug("iPhone.name="..iPhone.name.."; devicePresence="..devicePresence + .."; iPh pos=("..iPhone.location.latitude..", "..iPhone.location.longitude..")") + if devicePresence ~= nil then + -- iPhone connu, on teste la position + distance=math.sqrt((111*(latMaison-iPhone.location.latitude))^2 + + (111*(lonMaison-iPhone.location.longitude))^2) + debug("Distance="..distance + ..", TimeStamp="..iPhone.location.timeStamp + ..", deltaT="..math.floor(os.time()-iPhone.location.timeStamp/1000).."s") + + ici = ((math.abs(latMaison-iPhone.location.latitude) <= skew) + and (math.abs(lonMaison-iPhone.location.longitude) <= skew)) + + if ici then + Allumer(devicePresence) + debug(iPhone.name.." est ici!") + else + Eteindre(devicePresence) + debug(iPhone.name.." est absent!") + end + end + end +end + +--Fin du script +return commandArray + diff --git a/lua/meteo.lua b/lua/meteo.lua new file mode 100644 index 0000000..f4bb1a8 --- /dev/null +++ b/lua/meteo.lua @@ -0,0 +1,44 @@ +-- Chargement de la bibliothèque Lua pour effectuer des requêtes HTTP +local http = require("socket.http") +local json = require("json") + +-- Fonction pour effectuer une requête HTTP et renvoyer le contenu JSON en tant que tableau +function getJsonFromUrl(url) + local response = http.request(url) -- Effectue la requête HTTP + return json.decode(response) -- Décode la réponse JSON en tant que tableau +end + +-- Fonction récursive pour rechercher une valeur dans un tableau multidimensionnel +function searchValueInTable(value, tbl) + for k, v in pairs(tbl) do + if v == value then + return k -- Retourne la clé si la valeur est trouvée + elseif type(v) == "table" then + local result = searchValueInTable(value, v) -- Appel récursif si la valeur est un tableau + if result then + return k .. "." .. result -- Retourne la clé trouvée concaténée avec la clé actuelle + end + end + end + return nil -- Retourne nil si la valeur n'est pas trouvée +end + +-- Exemple d'utilisation +local url = "http://api.openweathermap.org/data/2.5/weather?q=La gacilly,fr&APPID=feba3f4d926db3b358a25ec782bd1c8b&lang=FR&units=metric" -- URL à appeler +local jsonData = getJsonFromUrl(url) -- Appel de la fonction pour obtenir le tableau JSON + +-- Affichage du contenu du tableau JSON +for k, v in pairs(jsonData) do + print(k, v) +end + +-- Recherche d'une valeur spécifique dans le tableau JSON +local searchValue = "valeurRecherchee" +local searchResult = searchValueInTable(searchValue, jsonData) + +if searchResult then + print("La valeur", searchValue, "a été trouvée à la clé", searchResult) +else + print("La valeur", searchValue, "n'a pas été trouvée dans le tableau") +end + diff --git a/lua/modules.lua b/lua/modules.lua new file mode 100644 index 0000000..dbb6f0e --- /dev/null +++ b/lua/modules.lua @@ -0,0 +1,1035 @@ +--[[ + + + +bibliothèque de fonctions pour domoticz +utiles à la réalisation de scripts d'automation en langage lua + +/!\ certaines fonctions ne fonctionneront pas sous windows. + +copier ce qui se trouve entre les 2 lignes ci dessous, en début de tout vos script +pour charger ce fichier et pouvoir en utiliser les fonctions + + +-------------------------------------------------------------------------------------------------------- + + +-- chargement des modules (http://easydomoticz.com/forum/viewtopic.php?f=17&t=3940) +dofile('/home/pi/domoticz/scripts/lua/modules.lua') + +local debug = true -- true pour voir les logs dans la console log Dz ou false pour ne pas les voir + + +-------------------------------------------------------------------------------------------------------- + + +]] + + +-------------------------------- +------ USER SETTINGS ------ +-------------------------------- + +-- domoticz +domoticzIP = '192.168.22.100' --'127.0.0.1' +domoticzPORT = '8080' +domoticzUSER = '' -- nom d'utilisateur +domoticzPSWD = '' -- mot de pass +domoticzPASSCODE = '' -- pour interrupteur protégés +domoticzURL = 'http://'..domoticzIP..':'..domoticzPORT + + + +-------------------------------- +------ END ------ +-------------------------------- + + +-- chemin vers le dossier lua et curl +if (package.config:sub(1,1) == '/') then + -- system linux + luaDir = debug.getinfo(1).source:match("@?(.*/)") + curl = '/usr/bin/curl -m 15 ' -- ne pas oublier l'espace à la fin +else + -- system windows + luaDir = string.gsub(debug.getinfo(1).source:match("@?(.*\\)"),'\\','\\\\') + -- download curl : https://bintray.com/vszakats/generic/download_file?file_path=curl-7.54.0-win32-mingw.7z + curl = 'c:\\Programs\\Curl\\curl.exe ' -- ne pas oublier l'espace à la fin +end + +-- chargement du fichier JSON.lua +json = assert(loadfile(luaDir..'JSON.lua'))() + +--time.hour ou time.min ou time.sec +--ex : if (time.hour == 17 and time.min == 05) then +time = os.date("*t") + +-- retourne l'heure actuelle ex: "12:45" +heure = string.sub(os.date("%X"), 1, 5) + +-- retourne la date ex: "01:01" +date = os.date("%d:%m") + +-- retourne l'heure du lever de soleil ex: "06:41" +leverSoleil = string.sub(os.date("!%X",60*timeofday['SunriseInMinutes']), 1, 5) + +-- retourne l'heure du coucher de soleil ex: "22:15" +coucherSoleil = string.sub(os.date("!%X",60*timeofday['SunsetInMinutes']), 1, 5) + +-- retourne le jour actuel en français ex: "mardi" +days = {"dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"} +jour = days[(os.date("%w")+1)] + +-- retourne VRAI si la semaine est paire +-- usage : +-- if semainePaire() then .. +function semainePaire() + local tm = os.time() + local function getYearBeginDayOfWeek() + yearBegin = os.time{year=os.date("*t",tm).year,month=1,day=1} + yearBeginDayOfWeek = tonumber(os.date("%w",yearBegin)) + -- sunday correct from 0 -> 7 + if(yearBeginDayOfWeek == 0) then yearBeginDayOfWeek = 7 end + return yearBeginDayOfWeek + end + local function getDayAdd() + yearBeginDayOfWeek = getYearBeginDayOfWeek(tm) + if(yearBeginDayOfWeek < 5 ) then + -- first day is week 1 + dayAdd = (yearBeginDayOfWeek - 2) + else + -- first day is week 52 or 53 + dayAdd = (yearBeginDayOfWeek - 9) + end + return dayAdd + end + dayOfYear = os.date("%j",tm) + dayAdd = getDayAdd(tm) + dayOfYearCorrected = dayOfYear + dayAdd + if(dayOfYearCorrected < 0) then + -- week of last year - decide if 52 or 53 + lastYearBegin = os.time{year=os.date("*t",tm).year-1,month=1,day=1} + lastYearEnd = os.time{year=os.date("*t",tm).year-1,month=12,day=31} + dayAdd = getDayAdd(lastYearBegin) + dayOfYear = dayOfYear + os.date("%j",lastYearEnd) + dayOfYearCorrected = dayOfYear + dayAdd + end + weekNum = math.floor((dayOfYearCorrected) / 7) + 1 + if( (dayOfYearCorrected > 0) and weekNum == 53) then + -- check if it is not considered as part of week 1 of next year + nextYearBegin = os.time{year=os.date("*t",tm).year+1,month=1,day=1} + yearBeginDayOfWeek = getYearBeginDayOfWeek(nextYearBegin) + if(yearBeginDayOfWeek < 5 ) then + weekNum = 1 + end + end + return weekNum%2 == 0 +end + + +-- il fait jour +dayTime = timeofday['Daytime'] +-- il fait nuit +nightTime = timeofday['Nighttime'] + +-- température +function getTemp(device) + return round(tonumber(otherdevices_temperature[device]),1) +end + +-- humidité +function getHum(device) + return round(tonumber(otherdevices_humidity[device]),1) +end + +-- humidité moyenne +function humMoy(device) + local monthLog = assert(io.popen(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..'/json.htm?range=month&sensor=temp&type=graph&idx='..otherdevices_idx[device]..'"')) + local list = monthLog:read('*all') + monthLog:close() + local data = ReverseTable(json:decode(list).result) + return(round(data[1].hu)) +end + +-- humidité absolue +function humAbs(t,hr) +-- https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/ +-- Formule pour calculer l'humidité absolue +-- Dans la formule ci-dessous, la température (T) est exprimée en degrés Celsius, l'humidité relative (hr) est exprimée en%, et e est la base des logarithmes naturels 2.71828 [élevée à la puissance du contenu des crochets]: +-- Humidité absolue (grammes / m3 ) = (6,122 * e^[(17,67 * T) / (T + 243,5)] * rh * 2,1674))/(273,15 + T) +-- Cette formule est précise à 0,1% près, dans la gamme de température de -30 ° C à + 35 ° C + return round((6.112 * math.exp((17.67 * t)/(t+243.5)) * hr * 2.1674)/ (273.15 + t),1) +end + +-- set setpoint (faster way) +function setPoint(device,value) + os.execute(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..'/json.htm?type=command¶m=udevice&idx='..otherdevices_idx[device]..'&nvalue=0&svalue='..value..'" &') +end + +function dimUp15(device) + -- 15 step + switchOn(device, constrain(otherdevices_svalues[device]+1,1,15)) +end + +function dimDown15(device) + -- 15 step + switchOn(device, constrain(otherdevices_svalues[device]-1,1,15)) +end + +function dimUp(device) + -- 100 step + switchOn(device, constrain(otherdevices_svalues[device]+10,10,100)) +end + +function dimDown(device) + -- 100 step + switchOn(device, constrain(otherdevices_svalues[device]-10,10,100)) +end + +-- vérifie s'il y a eu changement d'état +function stateChange(device) + if (uservariables['lastState_'..device] == nil) then + creaVar('lastState_'..device,otherdevices[device]) + log('stateChange : création variable manquante lastState_'..device,debug) + return false + elseif (devicechanged[device] == nil) then + return false + elseif (devicechanged[device] == uservariables['lastState_'..device]) then + return false + else + duree = lastSeen(uservariables_lastupdate['lastState_'..device]) + updateVar('lastState_'..device,otherdevices[device]) + return otherdevices[device] + end +end + +-- convertion degrés en direction cardinale +function wind_cardinals(deg) + local cardinalDirections = { + ['N'] = {348.75, 360}, + ['N'] = {0, 11.25}, + ['NNE'] = {11.25, 33.75}, + ['NE'] = {33.75, 56.25}, + ['ENE'] = {56.25, 78.75}, + ['E'] = {78.75, 101.25}, + ['ESE'] = {101.25, 123.75}, + ['SE'] = {123.75, 146.25}, + ['SSE'] = {146.25, 168.75}, + ['S'] = {168.75, 191.25}, + ['SSW'] = {191.25, 213.75}, + ['SW'] = {213.75, 236.25}, + ['WSW'] = {236.25, 258.75}, + ['W'] = {258.75, 281.25}, + ['WNW'] = {281.25, 303.75}, + ['NW'] = {303.75, 326.25}, + ['NNW'] = {326.25, 348.75} + } + local cardinal + for dir, angle in pairs(cardinalDirections) do + if (deg >= angle[1] and deg < angle[2]) then + cardinal = dir + break + end + end + return cardinal +end + +-- dump all variables supplied to the script +-- usage +-- LogVariables(_G,0,'') +function LogVariables(x,depth,name) + for k,v in pairs(x) do + if (depth>0) or ((string.find(k,'device')~=nil) or (string.find(k,'variable')~=nil) or + (string.sub(k,1,4)=='time') or (string.sub(k,1,8)=='security')) then + if type(v)=="string" then print(name.."['"..k.."'] = '"..v.."'") end + if type(v)=="number" then print(name.."['"..k.."'] = "..v) end + if type(v)=="boolean" then print(name.."['"..k.."'] = "..tostring(v)) end + if type(v)=="table" then LogVariables(v,depth+1,k); end + end + end +end + +-- os.execute() output or web page content return +-- usage +-- local resultat = os.capture(cmd , true) +-- print('resultat: ' .. resultat) +function os.capture(cmd, raw) + local f = assert(io.popen(cmd, 'r')) + local s = assert(f:read('*a')) + f:close() + if raw then return s end + s = string.gsub(s, '^%s+', '') + s = string.gsub(s, '%s+$', '') + s = string.gsub(s, '[\n\r]+', ' ') + return s +end + +-- retourne le type de la variable +-- 'string' , 'number' , 'table' +function typeof(var) + local _type = type(var); + if(_type ~= "table" and _type ~= "userdata") then + return _type; + end + local _meta = getmetatable(var); + if(_meta ~= nil and _meta._NAME ~= nil) then + return _meta._NAME; + else + return _type; + end +end + +-- affiche les logs en bleu sauf si debug est spécifié à false +function log(txt,debug) + if (debug ~= false) then + --print(""..txt.."") + print(txt) + end +end + +-- affiche les logs en rouge sauf si debug est spécifié à false +function warn(txt,debug) + if (debug ~= false) then + --print(""..txt.."") + print(txt) + end +end + +-- écriture dans un fichier texte dans le dossier lua +function logToFile(fileName,data) + f = assert(io.open(luaDir..fileName..'.txt',"a")) + f:write(os.date("%c")..' '..data..'\n') + f:close() +end + +-- teste l'existance d'un fichier +function file_exists(file) + local f = io.open(file, "rb") + if f then f:close() end + return f ~= nil +end + +-- retourne le nom du switch selon son IDX +function getDeviceName(deviceIDX) + for i, v in pairs(otherdevices_idx) do + if v == deviceIDX then + return i + end + end + return 0 +end + +-- get all lines from a file, returns an empty +-- list/table if the file does not exist +function lines_from(file) + if not file_exists(luaDir..file..'.txt') then return {} end + lines = {} + for line in io.lines(luaDir..file..'.txt') do + lines[#lines + 1] = line + end + return lines +end + +-- encode du texte pour le passer dans une url +function url_encode(str) + if (str) then + str = string.gsub (str, "\n", "\r\n") + str = string.gsub (str, "([^%w %-%_%.%~])", + function (c) return string.format ("%%%02X", string.byte(c)) end) + str = string.gsub (str, " ", "+") + end + return str +end + +-- supprime les accents de la chaîne +function sans_accent(str) + if (str) then + str = string.gsub (str,"Ç", "C") + str = string.gsub (str,"ç", "c") + str = string.gsub (str,"[-èéêë']+", "e") + str = string.gsub (str,"[-ÈÉÊË']+", "E") + str = string.gsub (str,"[-àáâãäå']+", "a") + str = string.gsub (str,"[-@ÀÁÂÃÄÅ']+", "A") + str = string.gsub (str,"[-ìíîï']+", "i") + str = string.gsub (str,"[-ÌÍÎÏ']+", "I") + str = string.gsub (str,"[-ðòóôõö']+", "o") + str = string.gsub (str,"[-ÒÓÔÕÖ']+", "O") + str = string.gsub (str,"[-ùúûü']+", "u") + str = string.gsub (str,"[-ÙÚÛÜ']+", "U") + str = string.gsub (str,"[-ýÿ']+", "y") + str = string.gsub (str,"Ý", "Y") + end + return str +end + +-- retourne le temps en seconde depuis la dernière maj du péréphérique +function lastSeen(device) + timestamp = otherdevices_lastupdate[device] or device + y, m, d, H, M, S = timestamp:match("(%d+)-(%d+)-(%d+) (%d+):(%d+):(%d+)") + difference = os.difftime(os.time(), os.time{year=y, month=m, day=d, hour=H, min=M, sec=S}) + return difference +end + +-- contraindre +function constrain(x, a, b) + if (x < a) then + return a + elseif (x > b) then + return b + else + return x + end +end + +-- arrondire +function round(num, dec) + if num == 0 then + return 0 + else + local mult = 10^(dec or 0) + return math.floor(num * mult + 0.5) / mult + end +end + +-- met le script en pause (fortement déconseillé) +-- usage +-- sleep(10) -- pour mettre en pause 10 secondes +function sleep(n) + os.execute('sleep '..n) +end + +-- création de variable utilisateur +-- usage +-- creaVar('toto','10') -- pour créer une variable nommée toto comprenant la valeur 10 +function creaVar(name,value) + local api = '/json.htm?type=command¶m=adduservariable' + local name = '&vname='..url_encode(name) + local vtype = '&vtype=2' + local value = '&vvalue='..url_encode(value) + api = api..name..vtype..value + os.execute(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..api..'" &') +end + +-- update an existing variable +function updateVar(name,value) + local api = '/json.htm?type=command¶m=updateuservariable' + local name = '&vname='..url_encode(name) + local vtype = '&vtype=2' + local value = '&vvalue='..url_encode(value) + api = api..name..vtype..value + os.execute(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..api..'" &') +end + +-- envoie dans un capteur text une chaîne de caractères +-- le text sera intercepté et lu par la custom page grâce à sa fonction MQTT +-- usage +-- speak('tts','bonjour nous sommes dimanche') +function speak(TTSDeviceName,txt) + commandArray[#commandArray+1] = {['OpenURL'] = domoticzIP..":"..domoticzPORT..'/json.htm?type=command¶m=udevice&idx='..otherdevices_idx[TTSDeviceName]..'&nvalue=0&svalue='..url_encode(txt)} +end + +-- récupère les infos json du périphérique +-- usage +-- local lampe = jsonInfos('ma lampe') +-- print(lampe.Name) +-- print(lampe.Status) +-- etc.. +function jsonInfos(device) + local rid = assert(io.popen(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..'/json.htm?type=devices&rid='..otherdevices_idx[device]..'"')) + local list = rid:read('*all') + rid:close() + return json:decode(list).result[1] +end + +-- parcours la table dans l'ordre +function spairs(t) + local keys = {} + for k in pairs(t) do keys[#keys+1] = k end + table.sort(keys) + local i = 0 + return function() + i = i + 1 + if keys[i] then + return keys[i], t[keys[i]] + end + end +end + +-- Renverse une table +function ReverseTable(t) + local reversedTable = {} + local itemCount = #t + for k, v in ipairs(t) do + reversedTable[itemCount + 1 - k] = v + end + return reversedTable +end + +-- affiche le contenu d'une table +--[[ + + Author: Julio Manuel Fernandez-Diaz + Date: January 12, 2007 + (For Lua 5.1) + + Modified slightly by RiciLake to avoid the unnecessary table traversal in tablecount() + + Formats tables with cycles recursively to any depth. + The output is returned as a string. + References to other tables are shown as values. + Self references are indicated. + + The string returned is "Lua code", which can be procesed + (in the case in which indent is composed by spaces or "--"). + Userdata and function keys and values are shown as strings, + which logically are exactly not equivalent to the original code. + + This routine can serve for pretty formating tables with + proper indentations, apart from printing them: + + print(table_show(t, "t")) -- a typical use + + Heavily based on "Saving tables with cycles", PIL2, p. 113. + + Arguments: + t is the table. + name is the name of the table (optional) + indent is a first indentation (optional). +]] +function table_show(t, name, indent) + local cart -- a container + local autoref -- for self references + + --[[ counts the number of elements in a table + local function tablecount(t) + local n = 0 + for _, _ in pairs(t) do n = n+1 end + return n + end + ]] + -- (RiciLake) returns true if the table is empty + local function isemptytable(t) return next(t) == nil end + + local function basicSerialize (o) + local so = tostring(o) + if type(o) == "function" then + local info = debug.getinfo(o, "S") + -- info.name is nil because o is not a calling level + if info.what == "C" then + return string.format("%q", so .. ", C function") + else + -- the information is defined through lines + return string.format("%q", so .. ", defined in (" .. + info.linedefined .. "-" .. info.lastlinedefined .. + ")" .. info.source) + end + elseif type(o) == "number" or type(o) == "boolean" then + return so + else + return string.format("%q", so) + end + end + + local function addtocart (value, name, indent, saved, field) + indent = indent or "" + saved = saved or {} + field = field or name + + cart = cart .. indent .. field + + if type(value) ~= "table" then + cart = cart .. " = " .. basicSerialize(value) .. ";\n" + else + if saved[value] then + cart = cart .. " = {}; -- " .. saved[value] + .. " (self reference)\n" + autoref = autoref .. name .. " = " .. saved[value] .. ";\n" + else + saved[value] = name + --if tablecount(value) == 0 then + if isemptytable(value) then + cart = cart .. " = {};\n" + else + cart = cart .. " = {\n" + for k, v in pairs(value) do + k = basicSerialize(k) + local fname = string.format("%s[%s]", name, k) + field = string.format("[%s]", k) + -- three spaces between levels + addtocart(v, fname, indent .. " ", saved, field) + end + cart = cart .. indent .. "};\n" + end + end + end + end + + name = name or "table" + if type(t) ~= "table" then + return name .. " = " .. basicSerialize(t) + end + cart, autoref = "", "" + addtocart(t, name, indent) + return cart .. autoref +end + +-- retourne la table des derniers log (première ligne = dernier log) +function lastLogEntry() + local rid = assert(io.popen(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..'/json.htm?type=command¶m=getlog"')) + local list = rid:read('*all') + rid:close() + local tableau = json:decode(list).result + return ReverseTable(tableau) +end + +-- notification pushbullet +-- usage: +-- pushbullet('test','ceci est un message test') +function pushbullet(title,body) + local settings = assert(io.popen(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..'/json.htm?type=settings"')) + local list = settings:read('*all') + settings:close() + local pushbullet_key = json:decode(list).PushbulletAPI + os.execute(curl..'-H \'Access-Token:'..pushbullet_key..'\' -H \'Content-Type:application/json\' --data-binary \'{"title":"'..title..'","body":"'..body..'","type":"note"}\' -X POST "https://api.pushbullet.com/v2/pushes"') +end + +-- switch On a device and set level if dimmmable +function switchOn(device,level) + local api = '/json.htm?type=command¶m=switchlight' + local idx = '&idx='..otherdevices_idx[device] + local cmd + if level ~= nil then + cmd = '&switchcmd=Set%20Level&level='..level + else + cmd = '&switchcmd=On' + end + local passcode = '&passcode='..domoticzPASSCODE + api = api..idx..cmd..passcode + os.execute(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..api..'" &') +end + +-- switch On a devive for x secondes +function switchOnFor(device, secs) + switchOn(device) + commandArray[#commandArray+1] = {[device] = "Off AFTER "..secs} +end + +-- switch Off a device +function switchOff(device) + local api = '/json.htm?type=command¶m=switchlight' + local idx = '&idx='..otherdevices_idx[device] + local cmd = '&switchcmd=Off' + local passcode = '&passcode='..domoticzPASSCODE + api = api..idx..cmd..passcode + os.execute(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..api..'" &') +end + +-- Toggle a device +function switch(device) + local api = '/json.htm?type=command¶m=switchlight' + local idx = '&idx='..otherdevices_idx[device] + local cmd = '&switchcmd=Toggle' + local passcode = '&passcode='..domoticzPASSCODE + api = api..idx..cmd..passcode + os.execute(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..api..'" &') +end + +-- switch On a group or scene +function groupOn(device) + local api = '/json.htm?type=command¶m=switchscene' + local idx = '&idx='..otherdevices_scenesgroups_idx[device] + local cmd = '&switchcmd=On' + local passcode = '&passcode='..domoticzPASSCODE + api = api..idx..cmd..passcode + os.execute(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..api..'" &') +end + +-- switch Off a group +function groupOff(device) + local api = '/json.htm?type=command¶m=switchscene' + local idx = '&idx='..otherdevices_scenesgroups_idx[device] + local cmd = '&switchcmd=Off' + local passcode = '&passcode='..domoticzPASSCODE + api = api..idx..cmd..passcode + os.execute(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..api..'" &') +end + +-- Set switch to Stop +function switchStop(device) + local api = '/json.htm?type=command¶m=switchlight' + local idx = '&idx='..otherdevices_idx[device] + local cmd = '&switchcmd=Stop' + local passcode = '&passcode='..domoticzPASSCODE + api = api..idx..cmd..passcode + os.execute(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..api..'" &') +end + +-- Setup a color & brightness of an RGB(W) light +-- API : https://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s#Set_an_RGB.28W.29_light_to_a_certain_color_and_brightness +function setColorAndBrightness(device, color, brightness) + local api = '/json.htm?type=command¶m=setcolbrightnessvalue' + local idx = '&idx='..otherdevices_idx[device] + --local color = '&hue='..color + local color = '&hex='..color + local brightness = '&brightness='..brightness + local iswhite = '&iswhite=false' + local passcode = '&passcode='..domoticzPASSCODE + api = api..idx..color..brightness..iswhite..passcode + os.execute(curl..'-u '..domoticzUSER..':'..domoticzPSWD..' "'..domoticzURL..api..'" &') +end + +function KelvinToRGB(temp) + -- http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/ + temp = temp/100 + local red, green, blue + --Calculate Red: + if temp <= 66 then + red = 255 + else + red = constrain(round(329.698727446 * ((temp - 60) ^ -0.1332047592)),0,255) + end + --Calculate Green: + if temp <= 66 then + green = constrain(round(99.4708025861 * math.log(temp) - 161.1195681661),0,255) + else + green = constrain(round(288.1221695283 * ((temp - 60) ^ -0.0755148492)),0,255) + end + --Calculate Blue: + if temp >= 66 then + blue = 255 + else + if temp <= 19 then + blue = 0 + else + blue = constrain(round(138.5177312231 * math.log(temp - 10) - 305.0447927307),0,255) + end + end + return {red,green,blue} +end + +function RGBToHex(rgb) + -- https://gist.github.com/marceloCodget/3862929 + local hexadecimal = '' + for key, value in pairs(rgb) do + local hex = '' + while(value > 0)do + local index = math.fmod(value, 16) + 1 + value = math.floor(value / 16) + hex = string.sub('0123456789ABCDEF', index, index) .. hex + end + if(string.len(hex) == 0)then + hex = '00' + elseif(string.len(hex) == 1)then + hex = '0' .. hex + end + hexadecimal = hexadecimal .. hex + end + return hexadecimal +end + +function suntimeToKelvin() + -- http://easydomoticz.com/forum/viewtopic.php?f=10&t=6160 + local mini = 1900 + local maxi = 6600 + local delta = maxi - mini + local wakeup = 60*timeofday['SunriseInMinutes'] + local goodnight = 60*timeofday['SunsetInMinutes'] + local periode = goodnight - wakeup + local offset = wakeup-periode/2 + local color = mini + local time = os.date("*t") + local now = 60*(time.hour*60 + time.min) + if now >= wakeup and now < goodnight then + color = math.floor((maxi-delta/2)+(delta/2)*math.cos((now-offset)*2*math.pi/periode)+0.5) + end + return color +end + +-- régulation chauffage (PID) +--[[ + + usage: + + local pid={} + pid['debug'] = true -- true pour voir les logs dans la console log Dz ou false pour ne pas les voir + pid['zone'] = 'salon' -- nom de la zone pour affichage dans les logs et ditinction de variables + pid['sonde'] = 'salon' -- Nom de la sonde de température + pid['OnOff'] = 'chauffage' -- Nom de l'interrupteur virtuel de mise en route (hivers/été) + pid['thermostat'] = 'th_salon' -- consigne ou 'nom' de l'interrupteur virtuel de thermostat + -- actionneur + pid['radiateur'] = 'radiateur salon' -- Nom de l'interrupteur de chauffage + pid['invert'] = false -- si On et Off doivent être inversé ou non + + -- PID -- + pid['Kp'] = 70 -- Coefficient proportionnel + pid['Ki'] = 8 -- Coefficient intégrateur + pid['Kd'] = 3 -- Coefficient dérivateur + + pid['cycle'] = 15 -- temps en minute d'un cycle PID + pid['secu'] = 60 -- temps mini en seconde entre 2 ordres opposés + + commandArray = {} + compute(pid) + return commandArray + +]] +function compute(pid) + local init = 0 + + -- récupération température + local temp = getTemp(pid['sonde']) + -- récupération température ext + local temp_ext = nil + if pid['sonde_ext'] ~= '' and pid['sonde_ext'] ~= nil then + temp_ext = getTemp(pid['sonde_ext']) + end + + -- création variable : 4 dernières températures + if (uservariables['PID_temps_'..pid['zone']] == nil ) then + creaVar('PID_temps_'..pid['zone'],string.rep(temp..';',3)..temp) + init = 1 + end + -- création variable : intégrale + if (uservariables['PID_integrale_'..pid['zone']] == nil ) then + creaVar('PID_integrale_'..pid['zone'],'0') + init = 1 + end + + if init == 1 then + log('PID '..pid['zone']..' initialisation..',pid['debug']) + do return end + end + + -- définition des variables locales + local moy_erreur = 0 + local n = 1 + local somme_erreurs = 0 + local heatTime + local marche + local arret + local tmp = {} + + -- définition des commandes marche/arrêt + if pid['invert'] then + marche = 'Off' ; arret = 'On' + else + marche = 'On' ; arret = 'Off' + end + + -- à chaque cycle + if ( time.min%pid['cycle'] == 0 ) then + + -- maj des 4 dernières temps + local temps = string.match(uservariables['PID_temps_'..pid['zone']],";([^%s]+)")..";"..temp + commandArray[#commandArray+1] = {['Variable:PID_temps_'..pid['zone']] = temps} + + -- si l'on veut chauffer + if ( otherdevices[pid['OnOff']] == 'On' ) then + + -- récupération de la consigne + local consigne = tonumber(otherdevices_svalues[pid['thermostat']]) or pid['thermostat'] + -- calcul de l'erreur + local erreur = consigne-temp + -- calcul intégrale auto consumée et moyenne erreur glissante + temps:gsub("([+-]?%d+%.*%d*)",function(t) + tmp[n] = tonumber(t) + err = tonumber(consigne-t) + somme_erreurs = somme_erreurs+err + moy_erreur = moy_erreur+err*n^3 + n = n+1 + end) + + somme_erreurs = round(constrain(somme_erreurs,0,255),1) + moy_erreur = round(moy_erreur/100,2) + + -- calcul de la dérivée (régression linéaire - méthode des moindres carrés) + local delta_erreurs = round((4*(4*tmp[1]+3*tmp[2]+2*tmp[3]+tmp[4])-10*(tmp[1]+tmp[2]+tmp[3]+tmp[4]))/20,2) + + -- aux abords de la consigne, passage au second systême integrale + if math.abs(somme_erreurs) < 2 then + somme_erreurs = tonumber(uservariables['PID_integrale_'..pid['zone']]) + -- re calcule intégrale si hors hysteresis + -- à moins d'un dixièmes de degré d'écart avec la consigne + -- le ratrapage est considéré OK, l'intégrale n'est pas recalculée + if math.abs(erreur) > 0.11 then + -- calcule intégrale + somme_erreurs = round(constrain(somme_erreurs+erreur/2,0,5),2) + -- maj + commandArray[#commandArray+1] = {['Variable:PID_integrale_'..pid['zone']] = tostring(somme_erreurs)} + end + end + + -- boucle ouverte, + -- modification dynamique des paramètres de régulation suivant température extérieure + local Kb = 0 + if temp_ext ~= nil then + Kb = pid['Kb'] * (consigne - temp_ext - pid['ref']) / 100 + end + pid['Kp'] = round(pid['Kp'] + pid['Kp'] * Kb) + pid['Ki'] = round(pid['Ki'] + pid['Ki'] * Kb) + pid['Kd'] = round(pid['Kd'] + pid['Kd'] * Kb) + + -- calcul pid + local P = round(pid['Kp']*moy_erreur,2) + local I = round(pid['Ki']*somme_erreurs,2) + local D = round(pid['Kd']*delta_erreurs,2) + + -- calcul de la commande en % + local commande = round(constrain(P+I+D,0,100)) + + -- calcul du temps de fonctionnement + if commande == 100 then + -- débordement de 20s pour ne pas couper avant recalcule + heatTime = (pid['cycle']*60)+20 + elseif commande > 0 then + -- secu mini maxi + heatTime = round(constrain(commande*pid['cycle']*0.6,pid['secu'],(pid['cycle']*60)-pid['secu'])) + elseif commande == 0 then + -- coupure retardée + heatTime = constrain(pid['secu']-lastSeen(pid['radiateur']),0,pid['secu']) + end + + -- AFTER n'aime pas 1 ou 2.. + if heatTime == 1 or heatTime == 2 then + heatTime = 0 + end + + -- action sur l'élément chauffant + if heatTime > 0 then + commandArray[#commandArray+1] = {[pid['radiateur']] = marche} + commandArray[#commandArray+1] = {[pid['radiateur']] = arret..' AFTER '..heatTime} + else + commandArray[#commandArray+1] = {[pid['radiateur']]=arret} + end + + -- journalisation + if pid['debug'] then + log('PID zone: '..string.upper(pid['zone'])) + if temp_ext ~= nil then + log('temperature ext: '..temp_ext..'°C') + end + log('température int: '..temp..'°C pour '..consigne..'°C souhaité') + log('Kp: '..pid['Kp']) + log('Ki: '..pid['Ki']) + log('Kd: '..pid['Kd']) + log('erreur: '..moy_erreur) + log('somme erreurs: '..somme_erreurs) + log('delta erreurs: '..delta_erreurs) + log('P: '..P) + log('I: '..I) + log('D: '..D) + log('cycle: '..pid['cycle']..'min (sécu: '..pid['secu']..'s)') + -- avertissement si secu dépasse 1/4 du cycle + if ((100*pid['secu'])/(60*pid['cycle'])>25) then + warn('sécu trop importante, ralonger durée de cycle..') + end + log('commande: '..commande..'% ('..string.sub(os.date("!%X",heatTime),4,8):gsub("%:", "\'")..'\")') + log('') + end + + -- maj sonde virtuelle + --commandArray[#commandArray+1] = {['UpdateDevice'] = otherdevices_idx[pid['sonde']..'_pid']..'|0|'..temp..';'..commande..';0'} + + end + + end + -- toutes les 15 minutes, si on ne veut pas chauffer + if ( time.min%15 == 0 and otherdevices[pid['OnOff']] == 'Off' ) then + + -- arrêt chauffage (renvoi commande systematique par sécurité) + commandArray[#commandArray+1] = {[pid['radiateur']] = arret..' AFTER '..constrain(pid['secu']-lastSeen(pid['radiateur']),3,pid['secu'])} + + -- maj sonde virtuelle + --commandArray[#commandArray+1] = {['UpdateDevice'] = otherdevices_idx[pid['sonde']..'_pid']..'|0|'..temp..';0;0'} + end + +end + +-- détermination automatique des paramètres de régulation PID +function autotune(pid) + + -- http://brettbeauregard.com/blog/2012/01/arduino-pid-autotune-library/ + + if devicechanged[pid['sonde']] then + + -- définition des commandes marche/arrêt + if pid['invert'] then + marche = 'Off' ; arret = 'On' + else + marche = 'On' ; arret = 'Off' + end + + -- récupération température + local temp = getTemp(pid['sonde']) + -- récupération consigne + local consigne = tonumber(otherdevices_svalues[pid['thermostat']]) or pid['thermostat'] + + -- hysteresis + if temp > consigne then + commandArray[#commandArray+1] = {[pid['radiateur']] = arret} + elseif temp < consigne then + commandArray[#commandArray+1] = {[pid['radiateur']] = marche} + end + + -- timestamp + local now = os.time() + + -- save all temps + logToFile(pid['zone']..'_temps',now..';'..temp) + + local max1 = consigne + local max2 = consigne + local mini = consigne + local max1_ts = now + local max2_ts = now + local mini_ts = now + local init = 0 + + -- recherche des valeurs mini/maxi + for _,v in spairs(ReverseTable(lines_from(pid['zone']..'_temps'))) do + t = tonumber(string.match(v,";([^%s]+)")) + ts = tonumber(string.match(v,"([^%s]+);")) + if t < mini and init == 0 then + init = 1 + elseif t > max2 and (init == 1 or init == 2) then + init = 2 + max2 = t + max2_ts = ts + elseif t < mini and (init == 2 or init == 3) then + init = 3 + mini = t + mini_ts = ts + elseif t > max1 and (init == 3 or init == 4) then + init = 4 + max1 = t + max1_ts = ts + elseif t <= consigne and init == 4 then + init = 5 + break + end + end + + -- autotune + local Pu = round(os.difftime(max2_ts, max1_ts) / 60) + local A = tonumber(max1 - mini) + local Ku = round(200 / (A * math.pi)) + local Kp = round(0.6 * Ku) + local Ki = round(1.2 * Ku / Pu * pid['cycle']) + local Kd = round(0.075 * Ku * Pu / pid['cycle']) + + -- journalisation + log('PID autotune '..string.upper(pid['zone'])) + if init == 5 then + log('max1: '..max1..' a '..os.date('%H:%M', max1_ts),pid['debug']) + log('mini: '..mini..' a '..os.date('%H:%M', mini_ts),pid['debug']) + log('max2: '..max2..' a '..os.date('%H:%M', max2_ts),pid['debug']) + log('Pu:'..Pu,pid['debug']) + log('A:'..A,pid['debug']) + log('Ku:'..Ku,pid['debug']) + log('Kp:'..Kp..' Ki:'..Ki..' Kd:'..Kd) + else + log('mesures en cours..') + end + + end +end diff --git a/lua/old/script_device_Energie.old b/lua/old/script_device_Energie.old new file mode 100755 index 0000000..3e71bf0 --- /dev/null +++ b/lua/old/script_device_Energie.old @@ -0,0 +1,481 @@ +-- demo device script +-- script names have three name components: script_trigger_name.lua +-- trigger can be 'time' or 'device', name can be any string +-- domoticz will execute all time and device triggers when the relevant trigger occurs +-- +-- copy this script and change the "name" part, all scripts named "demo" are ignored. +-- +-- Make sure the encoding is UTF8 of the file +-- +-- ingests tables: devicechanged, otherdevices,otherdevices_svalues +-- +-- device changed contains state and svalues for the device that changed. +-- devicechanged['yourdevicename']=state +-- devicechanged['svalues']=svalues string +-- +-- otherdevices and otherdevices_svalues are arrays for all devices: +-- otherdevices['yourotherdevicename']="On" +-- otherdevices_svalues['yourotherthermometer'] = string of svalues +-- +-- Based on your logic, fill the commandArray with device commands. Device name is case sensitive. +-- +-- Always, and I repeat ALWAYS start by checking for the state of the changed device. +-- If you would only specify commandArray['AnotherDevice']='On', every device trigger will switch AnotherDevice on, which will trigger a device event, which will switch AnotherDevice on, etc. +-- +-- The print command will output lua print statements to the domoticz log for debugging. +-- List all otherdevices states for debugging: +-- for i, v in pairs(otherdevices) do print(i, v) end +-- List all otherdevices svalues for debugging: +-- for i, v in pairs(otherdevices_svalues) do print(i, v) end +-- +-- TBD: nice time example, for instance get temp from svalue string, if time is past 22.00 and before 00:00 and temp is bloody hot turn on fan. +require "scripts/lua/functions" + +time = os.time() +annee = os.date('%Y',time) +mois = os.date('%m',time) +heures = tonumber(os.date('%H',time)) +minutes = tonumber(os.date('%M',time)) +secondes = tonumber(os.date('%S',time)) + +jour = tonumber(os.date('%w',time)) +jour_s = os.date('%d',time) + +heurmin = heures * 60 + minutes + +PUISSANCE_DELESTAGE = 750 -- Watts + +function update_meter(device, id, power, energy, index) + commandArray[index] = {['UpdateDevice'] = id .. "|0|" .. power .. ";" .. energy} +end + +local function round(num, dec) + --print("Round "..tostring(num)) + + return ( math.floor( tonumber(num) * 10^dec ) / 10^dec ) +end + +local function updatenum(dev, value1) + --local cmd = string.format("%d|0|%d", otherdevices_idx[dev], math.floor(value1)) + local cmd = tostring(otherdevices_idx[dev]).."|0|"..tostring(round(value1, 3)) + + table.insert (commandArray, { ['UpdateDevice'] = cmd } ) +end + +function getConsommationHC(idx) + date=annee..'-'..mois..'-'..jour_s + --date_end=annee..'-'..mois..'-'..math.floor(jour_s + 1) + + -- query = 'select max(value) - min(value) from Meter mc where DeviceRowID =' ..idx + -- .. ' and date like "' .. date ..'%"' + -- .. ' and (date >= "' .. date_deb.. ' 21:29:59" or date <= "'.. date_deb ..' 05:30:00")' + + + query = 'select sum(hc) from (select max(value) - min(value) as hc from Meter mc where DeviceRowID =' ..idx + .. ' and date like "' .. date ..'%"' + .. ' and (date >= "' .. date.. ' 21:29:59"' + .. ' and date < "' .. date ..' 23:59:59")' + .. ' union all' + .. ' select max(value) - min(value) as hc from Meter mc where DeviceRowID =' .. idx + .. ' and date like "' .. date ..'%"' + .. ' and (date < "' .. date ..' 05:30:00")' + .. ' and (date > "' .. date ..' 00:00:00")' + .. ') as c' + + --query = 'select max(value) - min(value) from Meter mc where DeviceRowID =' ..idx + -- .. ' and date like "' .. date ..'%"' + -- .. ' and not(date > "' .. date.. ' 05:29:59" and date <= "'.. date ..' 21:30:00")' + + + print("query="..query) + local bSuccess, aRows, iCount = executeQuery(idx, query) + + if aRows[1][1] then + print("Retour executeQuery "..tostring(bSuccess)..' '..aRows[1][1]) + return aRows[1][1] + end + print('retour à 0') + return 0 +end +function getConsommationHP(idx) + date=annee..'-'..mois..'-'..jour_s + query = 'select max(value) - min(value) from Meter mc where DeviceRowID =' ..idx + .. ' and date like "' .. date ..'%"' + .. ' and (date > "' .. date.. ' 05:29:59" and date <= "'.. date ..' 21:30:00")' + + --print("query="..query) + local bSuccess, aRows, iCount = executeQuery(idx, query) + + --print("Retour executeQuery "..tostring(bSuccess)..' '..aRows[1][1]) + return aRows[1][1] +end + +function deleteWrongData(idx) + + -- delete from MultiMeter where DeviceRowid = 1135 and date >= "2021-06-02 00:00:00" + -- and date like "2021-06-02 00:00%"; + date=annee..'-'..mois..'-'..jour_s + query = 'delete from MultiMeter where DeviceRowID =' ..idx + .. ' and date like "' .. date ..' 00:00%"' + .. ' and (date >= "' .. date.. ' 00:00:00")' + + print("query delete="..query) + local bSuccess, aRows, iCount = executeQuery(idx, query) + +end + + + +commandArray = {} + +-- ================================================================== +-- INTENSITE_GENERALE +-- ================================================================== +if (devicechanged['Oregon_Conso']) then + local tab = getValuesInTab('Oregon_Conso') + print("Conso "..otherdevices['Oregon_Conso']) + values = split(otherdevices['Oregon_Conso'], ";") + if (tonumber(values[1]) < 0) then + if (tonumber(values[1]) == -0.1) then + watt = - tonumber(values[2]) + else + watt = tonumber(values[1]) * 100 - tonumber(values[2]) + end + else + watt = (tonumber(values[1]) * 100 + tonumber(values[2])) --/ 1.42 + end + watt = watt - 80 + print("Conso "..tostring(watt)) + + --print("mesure"..otherdevices['INTENSITE_GENERALE']) + amp = watt / 230 --math.max(0,round(otherdevices['INTENSITE_GENERALE'],3) - 0.54) * 7 / 8 + + watt_conso = watt --* 0.9459 + updatenum('INTENSITE_GENERALE', amp) + + print("consommation Amp="..tostring(amp).." conso="..tostring(watt_conso)) + updatenum('CONSOMMATION_GENERALE', round(watt_conso,0)) + + local tab = getValuesInTab('SolaireProduction') + local watt_solaire = tonumber(tab[1]) + local watt_solaire_jour = otherdevices_svalues['SolaireProduction'] + print("Suivi "..tostring(watt_conso - watt_solaire)) + if (minutes%5 == 0) then + date = annee..'-'..mois..'-'..jour_s + + counter_conso = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select counter from Meter_Calendar where DeviceRowID='.. + otherdevices_idx['Consommation_Apparente']..' order by Date desc limit 1;"') + counter_conso=tonumber(counter_conso) or 0 + print('counter_conso='..counter_conso) + + value_conso = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select Value from Meter where DeviceRowID=='.. + otherdevices_idx['Consommation_Apparente']..' order by Date desc limit 1;"') + value_conso=tonumber(value_conso) or 0 + print('value_conso='..value_conso) + + + counter_solar = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select counter from Meter_Calendar where DeviceRowID='.. + otherdevices_idx['SolaireProduction']..' order by Date desc limit 1;"') + counter_solar=tonumber(counter_solar) or 0 + print('counter_solar='..counter_solar) + + value_solar = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select Value from Meter where DeviceRowID=='.. + otherdevices_idx['SolaireProduction']..' order by Date desc limit 1;"') + value_solar=tonumber(value_solar) or 0 + print('value_solar='..value_solar) + + counter_injection = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select counter from Meter_Calendar where DeviceRowID='.. + otherdevices_idx['INJECTION']..' order by Date desc limit 1;"') + counter_injection=tonumber(counter_injection) or 0 + print('counter_injection='..counter_injection) + + value_injection = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select Value from Meter where DeviceRowID=='.. + otherdevices_idx['INJECTION']..' order by Date desc limit 1;"') + value_injection=tonumber(value_injection) or 0 + print('value_injection='..value_injection) + + + counter_radiateur = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select counter from Meter_Calendar where DeviceRowID='.. + otherdevices_idx['Injection_Radiateur']..' order by Date desc limit 1;"') + counter_radiateur=tonumber(counter_radiateur) or 0 + print('counter_radiateur='..counter_radiateur) + + value_radiateur = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select Value from Meter where DeviceRowID=='.. + otherdevices_idx['Injection_Radiateur']..' order by Date desc limit 1;"') + value_radiateur=tonumber(value_radiateur) or 0 + print('value_radiateur='..value_radiateur) + + + cumul_solar = value_solar - counter_solar + cumul_injection = value_injection - counter_injection + consommation = value_conso - counter_conso + cumul_radiateur = value_radiateur - counter_radiateur + + print('conso='..consommation) + print('cumul_solar='..cumul_solar) + print('cumul_injection='..cumul_injection) + print('cumul_radiateur='..cumul_radiateur) + + if (cumul_solar > 0) then + print("auto consommation="..tostring( + round((100 * (cumul_solar - cumul_injection) / cumul_solar),1)) + ) + commandArray['AUTO_CONSOMMATION'] = otherdevices_idx['AUTO_CONSOMMATION'] ..'|0|' .. tostring( + round((100 * (cumul_solar - cumul_injection) / cumul_solar),1) + ) + updatenum('AUTO_CONSOMMATION', round((100 * (cumul_solar - cumul_injection) / cumul_solar),1) +) + + end + + if (consommation > 0) then + print("auto production="..tostring(100 * cumul_solar / (cumul_solar + consommation))) + updatenum('AUTO_PRODUCTION', round(100 * cumul_solar / (cumul_solar + consommation),1)) + + end + updatenum('COUVERTURE', round(100 * value_solar / (value_conso + value_solar),1)) + + + if (cumul_solar > 0) then + updatenum('Consommation_Efficace', round(100 *((cumul_solar - cumul_radiateur) / cumul_solar), 1)) + else + updatenum('Consommation_Efficace', 0) + end + end + +end + +if (devicechanged['Oregon_Solaire']) then + values2 = split(otherdevices['Mesure_Courant'], ";") + print("Solaire production 2"..otherdevices['Mesure_Courant']) + + local tab = getValuesInTab('Oregon_Solaire') + print("Solaire "..otherdevices['Oregon_Solaire']) + values = split(otherdevices['Oregon_Solaire'], ";") + if (tonumber(values[1]) < 0) then + if (tonumber(values[1]) == -0.1) then + watt = - tonumber(values[2]) + else + watt = tonumber(values[1]) * 100 - tonumber(values[2]) + end + else + watt = math.max(0, (tonumber(values[1]) * 100 + tonumber(values[2]))) + end + print("Solaire "..tostring(watt)) + + watt = tonumber(values2[1]) + if (watt > 1000) then + watt = 0; + end + --updatenum('SolaireIntensite', round(watt / 230,3)) + --updatenum('INTENSITE_GENERALE', round(watt / 230,3)) + watt = math.abs(watt) --- 56 + --if (watt < 0 or (heures <= 7 or heures >= 21)) then + -- watt = 0 + --end + + --print("Intensite solaire "..devicechanged['SolaireIntensite']) + amp = math.abs(watt / 230); --math.max(0, round(otherdevices['SolaireIntensite'],3) - 0.54) *1.18 + updatenum('SolaireIntensite', amp) + + print("# 2 # production amp="..tostring(amp).." watt="..tostring(watt)) + + updatenum('SolaireProduction', round(watt,1)) + + watt_solaire = math.abs(watt) + local tab = getValuesInTab('CONSOMMATION_GENERALE') + local watt_conso = tonumber(tab[1]) + local tab_r = getValuesInTab('Consommation_Apparente') + local watt_reel = tonumber(tab_r[1]) + if (watt_reel > 0) then + if watt_solaire > 0 then + updatenum('COUVERTURE_INSTANTANEE', round(100 * (watt_solaire / (watt_solaire + watt_reel)), 1)) + else + updatenum('COUVERTURE_INSTANTANEE', 0) + end + + else + updatenum('COUVERTURE_INSTANTANEE', 100) + end + +end + +if (devicechanged['Oregon_Conso_Reelle']) then + local tab = getValuesInTab('Oregon_Conso_Reelle') + print("Conso réelle "..otherdevices['Oregon_Conso_Reelle']) + values = split(otherdevices['Oregon_Conso_Reelle'], ";") + if (tonumber(values[1]) < 0) then + if (tonumber(values[1]) == -0.1) then + watt = - tonumber(values[2]) + else + watt = tonumber(values[1]) * 100 - tonumber(values[2]) + end + else + watt = math.max(0, (tonumber(values[1]) * 100 + tonumber(values[2]))) + end + watt = 20 + watt * 1.10 + print("Conso réelle "..tostring(watt)) + + updatenum('Consommation_Apparente', round(watt,0)) + + values = split(otherdevices['SolaireProduction'], ";") + print("Solaire production "..otherdevices['SolaireProduction']) + + watt_solaire = values[1] + + values2 = split(otherdevices['Mesure_Courant'], ";") + print("Solaire production 2"..otherdevices['Mesure_Courant']) + + watt_solaire = values[1] --+ values2[1] + + + print("Watt solaire "..watt_solaire) + if (watt < 0) then + updatenum('INJECTION', - round(watt,0)) + updatenum('TOTAL_INJECTION', - round(watt,0)) + --updatenum('Consommation_Apparente', 0) + updatenum('TOTAL_AUTOCONSOMMATION', round(watt_solaire - math.abs(watt), 0)) + else + updatenum('INJECTION', 0) + updatenum('TOTAL_INJECTION', 0) + updatenum('TOTAL_AUTOCONSOMMATION', round(watt_solaire,0)) + end + + -- ========================================================= + + --Calculate what the house is consuming + -- Get current date & time + t1 = os.time() + local currentDate = os.date("*t"); -- sets up currentDate.[table] + -- (currentDate.year [full], .month [1-12], .day [1-31], .hour [0-23], .min [0-59], .sec [0-59], .wday [0-6 {Sun-Sat}]) + sCurrentTime = currentDate.year .. "-" .. currentDate.month .. "-" .. currentDate.day .. " " .. currentDate.hour .. ":" .. currentDate.min .. ":" .. currentDate.sec + + counter_solar = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select counter from Meter_Calendar where DeviceRowID='.. + otherdevices_idx['SolaireProduction']..' order by Date desc limit 1;"') + counter_solar=tonumber(counter_solar) or 0 + print('counter_solar='..counter_solar) + + value_solar = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select Value from Meter where DeviceRowID=='.. + otherdevices_idx['SolaireProduction']..' order by Date desc limit 1;"') + value_solar=tonumber(value_solar) or 0 + print('value_solar='..value_solar) + + + --------------------------------------------------------------------------------------- + -- Solaire 2 + date = annee..'-'..mois..'-'..jour_s + + counter_solar2 = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select counter from Meter_Calendar where DeviceRowID='.. + otherdevices_idx['Mesure_Courant'].. + ' and date like "' .. date ..'%"'.. + ' order by Date desc limit 1;"') + counter_solar2=tonumber(counter_solar2) or 0 + print('counter_solar2='..counter_solar2) + + value_solar2 = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select Value from Meter where DeviceRowID=='.. + otherdevices_idx['Mesure_Courant'].. + ' and date like "' .. date ..'%"'.. + ' order by Date desc limit 1;"') + value_solar2=tonumber(value_solar2) or 0 + print('value_solar2='..value_solar2) + + -------------------------------------------------------------------------------------- + + + + watt_p1 = getConsommationHP(1123) or 0 + watt_p2 = getConsommationHC(1123) or 0 + local cmd = '1135|0|' + --USAGE1= energy usage meter tariff 1, This is an incrementing counter + --USAGE2= energy usage meter tariff 2, This is an incrementing counter + --RETURN1= energy return meter tariff 1, This is an incrementing counter + --RETURN2= energy return meter tariff 2, This is an incrementing counter + --CONS= actual usage power (Watt) + --PROD= actual return power (Watt) + .. tostring(math.floor(watt_p1)) .. ';' + .. tostring(math.floor(watt_p2)) .. ';' + -- + value_solar2 - counter_solar2 + .. tostring(math.floor(value_solar - counter_solar + value_solar2 - counter_solar2)) .. ';' + .. '0;' + .. tostring(math.floor(math.max(0,watt) + watt_solaire)).. ';' + .. tostring(math.floor(watt_solaire)) --math.floor(ConsumoEnergyBalance / 1000)) --round(watt,0)) + + print('Consommation_Reelle_2 '..cmd) + if heures == 23 and minutes == 59 and secondes >= 45 then + -- ignored + else + table.insert (commandArray, { ['UpdateDevice'] = cmd } ) + end + if heures == 00 and minutes == 05 and secondes <= 10 then + deleteWrongData(1135) + end + print('when light=' .. tostring(whenLight())) + + -- ========================================================= + + local cmd = '1136|0|' + --USAGE1= energy usage meter tariff 1, This is an incrementing counter + --USAGE2= energy usage meter tariff 2, This is an incrementing counter + --RETURN1= energy return meter tariff 1, This is an incrementing counter + --RETURN2= energy return meter tariff 2, This is an incrementing counter + --CONS= actual usage power (Watt) + --PROD= actual return power (Watt) + .. '0;' + .. '0;' + .. '0;' + .. '0;' + .. tostring(math.floor(math.max(0,watt))).. ';' + .. '0' --math.floor(ConsumoEnergyBalance / 1000)) --round(watt,0)) + table.insert (commandArray, { ['UpdateDevice'] = cmd } ) + updatenum('Non_Couvert_2', math.floor(math.max(0,watt))) + + -- ========================================================= + + + local debut_injection = -20 + local fin_injection = 10 + + if tonumber(watt_solaire) < 50 or uservariables["Dark"] == "True" then + commandArray['Dimmer'] = 'Set Level: 30' + else + if (watt < debut_injection and tonumber(watt_solaire) > 150) then + print("Allumage radiateur pour éviter l'injection " .. tostring(lastUpdateOfDevice('RadiateurBureau'))) + + if watt < debut_injection then + local quick_value=math.floor(math.abs(watt / (PUISSANCE_DELESTAGE / 100))) + print("quick_value plus="..tostring(quick_value)) + os.execute('curl "http://192.168.125.11/plus?value=' .. tostring(quick_value).. '"'); + else + commandArray['Dimmer'] = 'Set Level: 40' + end + else + print("Pas de consommation necessaire") + if (watt > 150) then + commandArray['Dimmer'] = 'Set Level: 30' + else + if (watt > fin_injection) then + local quick_value=math.floor(math.abs(watt / (PUISSANCE_DELESTAGE / 100))) + print("quick_value minus="..tostring(quick_value)) + os.execute('curl "http://192.168.125.11/minus?value=' .. tostring(quick_value).. '"'); + else + commandArray['Dimmer'] = 'Set Level: 50' + end + end + end + end + + command = 'curl -s "http://192.168.125.11"|grep "

"|awk -F">" \'{print $2}\'|awk -F"<" \'{print $1}\'' + local handle = io.popen(command) + local result = handle:read("*a") + handle:close() + print("result niveau d'injection= "..result) + updatenum('Injection_Radiateur', tonumber(result) * PUISSANCE_DELESTAGE / 100) + if (tonumber(result) == 1) then + commandArray['Dimmer'] = 'Set Level: 30' + end + +end + + +return commandArray + diff --git a/lua/old/script_device_Radiateur.old b/lua/old/script_device_Radiateur.old new file mode 100755 index 0000000..32e7ed8 --- /dev/null +++ b/lua/old/script_device_Radiateur.old @@ -0,0 +1,210 @@ +require "scripts/lua/functions" + +commandArray = {} + +--local switch = 'VoletCuisine' + +-- ------------------------------------------------------------------------------ +--recupere les minutes +-- ------------------------------------------------------------------------------ +time=os.time() +minutes=tonumber(os.date('%M',time)) +jour=tonumber(os.date('%w',time)) +heures=tonumber(os.date('%H',time)) +heurmin= heures * 60 + minutes + +-- ------------------------------------------------------------------------------ +-- Test temperature radiateur chambres +-- ------------------------------------------------------------------------------ +function gestionRadiateur( switchTemp, switchRadiateur, consigne) + + if (minutes % 10 ~= 5) then + return + end + + local last = lastUpdateOfDevice(switchRadiateur) + debug("--------------"..switchRadiateur.."-----------------------------------") + debug("delai="..tostring(delai).." last="..tostring(last)..' Chauffage='..otherdevices[switchRadiateur]) + debug("------------------------------------------------------------") + + if (last < 600) then + debug("Aucune action. Mise à jour trop récente.".." last="..tostring(last).." temp="..tostring(currentTemp).." / Consigne="..tostring(consigne)) + return + end + + local delta = 0.2 + + local currentTemp = tonumber(otherdevices_svalues[switchTemp]) + + local tempAbsence = tonumber(otherdevices_svalues['ConsigneAbsence']) + + local variation = variationTemp2(switchTemp, 10) -- variation des 10 dernières minutes + + local variationExt = uservariables['AugmentationTempExterieure'] + + local augmentation = variation * 60 / 10 --time -- ° par heure + + local ecart = consigne - currentTemp + + local estimation = 0.0 + if (augmentation > 0 and ecart > 0) then + estimation = 60 * ecart / augmentation + end + + debug("Retour augmentation="..tostring(augmentation).." ecart="..tostring(ecart)..'°C Estimation='..tostring(estimation).." minutes variationExt="..tostring(variationExt).."°C / heure") + +--2016-02-27 20:08:59.864 LUA: delai=180 last=37 +--2016-02-27 20:08:59.918 LUA: Retour variation=0.3 switch=RadiateurManon +--2016-02-27 20:08:59.918 LUA: CHECK Temperature Variation=0.3 switch=RadiateurManon currentTemp=18.3 tempAbsence=16 consigne=18.5 + + debug("Retour variation="..tostring(variation).." switch="..switchRadiateur..' lastUpdate='..tostring(lastUpdateOfDevice(switchRadiateur))) + debug('CHECK Temperature Variation='..tostring(variation)..' switch='..switchRadiateur..' currentTemp='..tostring(currentTemp).. ' tempAbsence='..tostring(tempAbsence)..' consigne='..tostring(consigne)) + + if otherdevices['ChauffageGeneral'] == 'Off' then + if (minutes%30 == 0) then + switchOffRadiateur(switchRadiateur) + debug("ChauffageGeneral Eteint. Demande extinction.") + else + debug("Radiateur ="..switchRadiateur.." Retour sans rien faire. ChauffageGeneral Eteint.") + end + end + if lastUpdateOfDevice(switchRadiateur) < delai then + debug("Radiateur ="..switchRadiateur.." Retour sans rien faire. Delai non atteint.") + return + end + -- Periode de vacances ou absence ==> hors gel + if (otherdevices['Vacances'] == 'On' or otherdevices['AbsenceFamille'] == 'On') then + if (currentTemp > 14) then + switchOffRadiateur(switchRadiateur) + --commandArray[switchRadiateur]='Off' + else + if variation <= 0 then + --commandArray[switchRadiateur]='On' + switchOnRadiateur(switchRadiateur) + end + end + debug ('CHECK Temperature chambre : Vacances -> ' ..otherdevices_svalues[switchTemp]..' switch='..switchRadiateur) + else + debug ('CHECK Temperature: Presence -> ' ..otherdevices_svalues[switchTemp]..' '..josdGetJourSemaine(jour)) + -- Température non atteinte + if (currentTemp < consigne) then + if variation <= 0.0 then + -- commandArray[switchRadiateur]='On' + switchOnRadiateur(switchRadiateur) + debug("Demande chauffe : "..tostring(currentTemp).." / "..tostring(consigne).." Variation="..tostring(variation)) + else + --switchIfNeeded(switchRadiateur, 'On') + -- Dépassement prévu dans le delai on coupe + if (estimation > 0 and estimation <= delai / 60 ) then + --commandArray[switchRadiateur] = 'Off' + switchOffRadiateur(switchRadiateur) + debug("Arrêt chauffage : Température sera atteinte dans le delai "..tostring(estimation).." Minutes") + else + debug("Aucune action. Chauffage en-cours."..tostring(currentTemp).." / "..tostring(consigne).." Variation="..tostring(variation)) + end + end + -- Température dépassée + else + -- Température supérieure + if (currentTemp >= consigne + delta or (estimation > 0 and estimation <= delai / 60 )) then + if (consigne == consigneAbsence) then + -- rien + switchIfNeeded(switchRadiateur,"Off") + else + if (variation > 0) then + if (variationExt <= 0) then + switchOffRadiateur(switchRadiateur) + debug("Demande arrêt. Température dépassée.") + else + switchIfNeeded(switchRadiateur,"Off") + debug("Aucune action. Augmentation due à température extérieure.") + end + end + end + else + -- Augmentation de la température non due à l'augmentation extérieure + if (variation > 0) then + -- Pas d'augmentation extérieure + if (variationExt <= 0) then + --commandArray[switchRadiateur]='Off' + switchOffRadiateur(switchRadiateur) + debug("Demande arrêt. Température atteinte et continue d'augmenter.") + else + switchIfNeeded(switchRadiateur,"Off") + debug("Aucune action. Augmentation due à température extérieure.") + end + else + -- Températue en baisse pas nécessaire d'envoyer + --switchOffRadiateur(switchRadiateur) + --commandArray[switchRadiateur]='Off' + --switchIfNeeded(switchRadiateur, 'Off') + switchIfNeeded(switchRadiateur,"Off") + debug("Aucune action. Temperature atteinte et pas d'augmentation. "..tostring(currentTemp).." / "..tostring(consigne).." Variation="..tostring(variation)) + end + end + end + end + debug("------------------------------------------------------------") +end + +-- ------------------------------------------------------ +-- Arrêt tous les radiateurs +-- ------------------------------------------------------ +if devicechanged['ChauffageGeneral'] then + if otherdevices['ChauffageGeneral'] == 'Off' then + for i = 1, 7 do + print("Arrêt radiateur="..radiateurs[i]) + commandArray[radiateurs[i]]='Off' + end + end +end + +-- ------------------------------------------------------ +-- Chambre de Manon +-- ------------------------------------------------------ +if devicechanged['ChambreManon'] or devicechanged['ConsigneConfortManon'] or devicechanged['ChauffageGeneral'] then + local consigne = tonumber(otherdevices_svalues['ConsigneConfortManon']) + gestionRadiateur('ChambreManon', 'RadiateurManon', consigne) +end + +-- ------------------------------------------------------ +-- Chambre de Theo +-- ------------------------------------------------------ +if devicechanged['ChambreTheo'] or devicechanged['ConsigneConfortTheo'] or devicechanged['ChauffageGeneral'] then + local consigne = tonumber(otherdevices_svalues['ConsigneConfortTheo']) + gestionRadiateur('ChambreTheo', 'RadiateurTheo', consigne) +end +-- ------------------------------------------------------ +-- Chambre parents +-- ------------------------------------------------------ +if devicechanged['Chambre'] or devicechanged['ConsigneConfortChambre'] or devicechanged['ChauffageGeneral'] then + local consigne = tonumber(otherdevices_svalues['ConsigneConfortChambre']) + gestionRadiateur('Chambre', 'RadiateurChambre', consigne) +end +-- ------------------------------------------------------ +-- Radiateur cuisine +-- ------------------------------------------------------ +if devicechanged['TemperatureBarometre'] or devicechanged['ConsigneConfortSalon'] or devicechanged['ChauffageGeneral'] then + local consigne = tonumber(otherdevices_svalues['ConsigneConfortSalon']) + gestionRadiateur('TemperatureBarometre', 'RadiateurCuisine', consigne) +end +-- ------------------------------------------------------ +-- Radiateur Salon +-- ------------------------------------------------------ +if devicechanged['TemperatureBarometre'] or devicechanged['ConsigneConfortSalon'] or devicechanged['ChauffageGeneral'] then + local consigne = tonumber(otherdevices_svalues['ConsigneConfortSalon']) + gestionRadiateur('TemperatureBarometre', 'RadiateurSalon1', consigne) + gestionRadiateur('TemperatureBarometre', 'RadiateurSalon2', consigne) +end + +-- ------------------------------------------------------ +-- Radiateur Bureau +-- ------------------------------------------------------ +if devicechanged['Bureau'] or devicechanged['ConsigneConfortBureau'] or devicechanged['ChauffageGeneral'] then + local consigne = tonumber(otherdevices_svalues['ConsigneConfortBureau']) + gestionRadiateur('Bureau', 'RadiateurBureau', consigne) + --gestionRadiateur('TemperatureBarometre', 'RadiateurSalon2', consigne) +end + + +return commandArray diff --git a/lua/old/script_device_demo.old b/lua/old/script_device_demo.old new file mode 100755 index 0000000..98e706c --- /dev/null +++ b/lua/old/script_device_demo.old @@ -0,0 +1,39 @@ +-- demo device script +-- script names have three name components: script_trigger_name.lua +-- trigger can be 'time' or 'device', name can be any string +-- domoticz will execute all time and device triggers when the relevant trigger occurs +-- +-- copy this script and change the "name" part, all scripts named "demo" are ignored. +-- +-- Make sure the encoding is UTF8 of the file +-- +-- ingests tables: devicechanged, otherdevices,otherdevices_svalues +-- +-- device changed contains state and svalues for the device that changed. +-- devicechanged['yourdevicename']=state +-- devicechanged['svalues']=svalues string +-- +-- otherdevices and otherdevices_svalues are arrays for all devices: +-- otherdevices['yourotherdevicename']="On" +-- otherdevices_svalues['yourotherthermometer'] = string of svalues +-- +-- Based on your logic, fill the commandArray with device commands. Device name is case sensitive. +-- +-- Always, and I repeat ALWAYS start by checking for the state of the changed device. +-- If you would only specify commandArray['AnotherDevice']='On', every device trigger will switch AnotherDevice on, which will trigger a device event, which will switch AnotherDevice on, etc. +-- +-- The print command will output lua print statements to the domoticz log for debugging. +-- List all otherdevices states for debugging: +-- for i, v in pairs(otherdevices) do print(i, v) end +-- List all otherdevices svalues for debugging: +-- for i, v in pairs(otherdevices_svalues) do print(i, v) end +-- +-- TBD: nice time example, for instance get temp from svalue string, if time is past 22.00 and before 00:00 and temp is bloody hot turn on fan. + +print('this will end up in the domoticz log') + +commandArray = {} +if (devicechanged['MyDeviceName'] == 'On' and otherdevices['MyOtherDeviceName'] == 'Off') then + commandArray['MyOtherDeviceName']='On' +end +return commandArray diff --git a/lua/old/script_time_DewPoint.old b/lua/old/script_time_DewPoint.old new file mode 100755 index 0000000..210b12c --- /dev/null +++ b/lua/old/script_time_DewPoint.old @@ -0,0 +1,143 @@ +--[[ +~/domoticz/scripts/lua/script_device_givre.lua +auteur : papoo +MAJ : 28/02/2018 +création : 06/05/2016 +Principe : +Calculer via les informations température et hygrométrie d'une sonde extérieure + le point de rosée ainsi que le point de givre +puis en comparant ensuite le point de givre et l'a température extérieure, création d'une alerte givre. +http://pon.fr/script-calcul-et-alerte-givre/ +http://easydomoticz.com/forum/viewtopic.php?f=21&t=1085&start=10#p17545 +https://github.com/papo-o/domoticz_scripts/blob/master/Lua/script_device_givre.lua +--]] + +-------------------------------------------- +------------ Variables à éditer ------------ +-------------------------------------------- +require "scripts/lua/functions" + +local debugging = true -- true pour voir les logs dans la console log Dz ou false pour ne pas les voir +local temp_ext = 'BarometreLaGacilly' -- nom de la sonde de température/humidité extérieure +local dev_dew_point = 'Point de rosee' -- nom de l'éventuel dummy température point de rosée si vous souhaitez le suivre sinon nil +local dev_freeze_point = 'Point de givre' -- nom de l'éventuel dummy température point de givre si vous souhaitez le suivre sinon nil +local dev_hum_abs_point = nil -- nom de l'éventuel dummy humidité absolue si vous souhaitez le suivre sinon nil +local dev_freeze_alert = 'Alerte givre' -- nom de l'éventuel dummy alert point de givre si vous souhaitez le suivre sinon nil + +-------------------------------------------- +----------- Fin variables à éditer --------- +-------------------------------------------- +local nom_script = 'Point de rosée et point de givrage' +local version = 1.2 -- version du script + +commandArray = {} + +-------------------------------------------- +---------------- Fonctions ----------------- +-------------------------------------------- +function voir_les_logs (s, debugging) + if (debugging) then + if s ~= nil then + debug ("".. tostring(s) ..""); + else + debug ("aucune valeur affichable"); + end + end +end +function round(value, digits) + if not value or not digits then + return nil + end + local precision = 10^digits + return (value >= 0) and + (math.floor(value * precision + 0.5) / precision) or + (math.ceil(value * precision - 0.5) / precision) +end +function dewPoint (T, RH) + local b,c = 17.67, 243.5 + --voir_les_logs("--- 1",debugging) + RH = math.max (tonumber(RH), 1e-3) + --voir_les_logs("--- 1",debugging) + local gamma = math.log (tonumber(RH)/100) + b * T / (c + T) + --voir_les_logs("--- 1",debugging) + return c * gamma / (b - gamma) +end +function freezing_point(dp, t) + if not dp or not t or dp > t then + return nil, " La température du point de rosée est supérieure à la température. Puisque la température du point de rosée ne peut être supérieure à la température de l'air , l\'humidité relative a été fixée à nil." + end + + T = t + 273.15 + Td = dp + 273.15 + return (Td + (2671.02 /((2954.61/T) + 2.193665 * math.log(T) - 13.3448))-T)-273.15 + +end + +function hum_abs(t,hr) + -- https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/ + -- Formule pour calculer l'humidité absolue + -- Dans la formule ci-dessous, la température (T) est exprimée en degrés Celsius, l'humidité relative (hr) est exprimée en%, et e est la base des logarithmes naturels 2.71828 [élevée à la puissance du contenu des crochets]: + -- Humidité absolue (grammes / m3 ) = (6,122 * e^[(17,67 * T) / (T + 243,5)] * rh * 2,1674))/(273,15 + T) + -- Cette formule est précise à 0,1% près, dans la gamme de température de -30 ° C à + 35 ° C + ha = round((6.112 * math.exp((17.67 * t)/(t+243.5)) * hr * 2.1674)/ (273.15 + t),1) + return ha +end + +-------------------------------------------- +-------------- Fin Fonctions --------------- +-------------------------------------------- + +time=os.date("*t") +if (time.min%15 == 0) then -- si script_time +--if devicechanged[temp_ext] then -- si script_device +--print("script_device_givre.lua") + print('valeurs '..otherdevices_svalues[temp_ext]); + voir_les_logs("=========== ".. nom_script .." (v".. version ..") ===========",debugging) + Temp, Humidity = otherdevices_svalues[temp_ext]:match("([^;]+);([^;]+)") + voir_les_logs("--- --- --- Température Ext : ".. Temp,debugging) + voir_les_logs("--- --- --- Humidité : ".. Humidity,debugging) + + if dev_dew_point ~= nil then + local dew = dewPoint(Temp,Humidity) + voir_les_logs("--- --- --- Dew point calculated : ".. tostring(dew),debugging) + DewPoint = round(dew,2) + voir_les_logs("--- --- --- Point de Rosée : ".. DewPoint,debugging) + commandArray[#commandArray+1] = {['UpdateDevice'] = otherdevices_idx[dev_dew_point] .. "|0|" .. DewPoint} -- Mise à jour point de rosée + end + --voir_les_logs("--- 1",debugging) + if dev_freeze_point ~= nil then + FreezingPoint = round(freezing_point(DewPoint, tonumber(Temp)),2) + voir_les_logs("--- --- --- Point de Givrage : ".. FreezingPoint,debugging) + commandArray[#commandArray+1] = {['UpdateDevice'] = otherdevices_idx[dev_freeze_point] .. "|0|" .. FreezingPoint} -- Mise à jour point de givrage + end + + --voir_les_logs("--- 2",debugging) + if dev_hum_abs_point ~= nil then + hum_abs_point = hum_abs(Temp, Humidity) + voir_les_logs("--- --- --- Humidité absolue : ".. hum_abs_point,debugging) + commandArray[#commandArray+1] = {['UpdateDevice'] = otherdevices_idx[dev_hum_abs_point] .. "|0|" .. hum_abs_point} -- Mise à jour humidité absolue + end + + --voir_les_logs("--- 3",debugging) + + if dev_freeze_alert ~= nil and time.hour == 7 and time.min >= 30 then + if(tonumber(Temp)<=1 and tonumber(FreezingPoint)<=0) then + voir_les_logs("--- --- --- Givre --- --- ---",debugging) + commandArray[#commandArray+1] = {['UpdateDevice'] = otherdevices_idx[dev_freeze_alert]..'|4|'..FreezingPoint} + commandArray['SendNotification'] = 'Alert#Présence de givre!' + elseif(tonumber(Temp)<=3 and tonumber(FreezingPoint)<=0)then + voir_les_logs("--- --- --- Risque de Givre --- --- ---",debugging) + commandArray[#commandArray+1] = {['UpdateDevice'] = otherdevices_idx[dev_freeze_alert]..'|2|'..FreezingPoint} + commandArray['SendNotification'] = 'Alert#Risque de givre!' + else + voir_les_logs("--- --- --- Aucun risque de Givre --- --- ---",debugging) + commandArray[#commandArray+1] = {['UpdateDevice'] = otherdevices_idx[dev_freeze_alert]..'|1|'..'Pas de givre'} + end + end +voir_les_logs("========= Fin ".. nom_script .." (v".. version ..") =========",debugging) +end + +return commandArray + + + diff --git a/lua/old/script_time_PluieNeige.old b/lua/old/script_time_PluieNeige.old new file mode 100755 index 0000000..5a08a17 --- /dev/null +++ b/lua/old/script_time_PluieNeige.old @@ -0,0 +1,262 @@ +-------------------------------------------------------------------------------- +-- Probabilite pluie neige +-------------------------------------------------------------------------------- + --[[ + name : script_time_probabilite_pluie.lua + auteur : papoo + version : 1.11 + date de création : 08/08/2016 + Date de mise à jour : 10/08/16 + Principe : Ce script a pour but d'interroger l'API du site https://www.wunderground.com/ toutes les heures afin de + récuperer les calculs de probabilités de pluie et de neige sur 36 heures pour une ville donnée. Cette API utilise une clé gratuite pour 500 requetes par heure + Il faut donc s’inscrire sur weatherunderground pour avoir accès à cette API + URL post : http://easydomoticz.com/forum/viewtopic.php?f=17&t=2301 + Ce script utilise Lua-Simple-XML-Parser https://github.com/Cluain/Lua-Simple-XML-Parser + ]]-- + -- ======================================================================== + -- Variables à éditer + -- ======================================================================== + local debugging = true -- true pour voir les logs dans la console log Dz ou false pour ne pas les voir + local countryCode="FRANCE" -- Votre countryCode, nécessaire pour l'API + local APIKEY="48a08328a93a18a1" -- Votre Key API Weather Underground de 16 caractères + local ville="Redon" -- Votre ville ou commune nécessaire pour l'API + -- L'api fournie 36 probabilités de pluie, 1 par heure. + local proba_pluie_h = {} -- Ajoutez, modifiez ou supprimez les variables proba_pluie_h[] + -- en changeant le N° entre [] correspondant à l'heure souhaitée pour l'associer au device concerné dans dz + proba_pluie_h[1]=328 -- renseigner l'id du device % probabilité pluie à 1 heure associé, nil si non utilisé + proba_pluie_h[2]=329 -- renseigner l'id du device % probabilité pluie à 2 heures associé, nil si non utilisé + proba_pluie_h[4]=nil -- renseigner l'id du device % probabilité pluie à 4 heures associé, nil si non utilisé + proba_pluie_h[6]=nil -- renseigner l'id du device % probabilité pluie à 6 heures associé, nil si non utilisé + proba_pluie_h[12]=nil -- renseigner l'id du device % probabilité pluie à 12 heures associé, nil si non utilisé + proba_pluie_h[24]=nil -- renseigner l'id du device % probabilité pluie à 24 heures associé, nil si non utilisé + -- L'api fournie 36 probabilités de neige, 1 par heure. + local proba_neige_h={} -- comme pour la pluie Ajoutez, modifiez ou supprimez les variables proba_neige_h[] + -- en changeant le N° entre [] correspondant à l'heure souhaitée pour l'associer au device concerné dans dz + proba_neige_h[1]=nil -- renseigner l'id du device % probabilité neige à 1 heure associé, nil si non utilisé + proba_neige_h[3]=nil -- renseigner l'id du device % probabilité neige à 2 heures associé, nil si non utilisé + proba_neige_h[6]=nil -- renseigner l'id du device % probabilité neige à 4 heures associé, nil si non utilisé + proba_neige_h[12]=nil -- renseigner l'id du device % probabilité neige à 6 heures associé, nil si non utilisé + proba_neige_h[24]=nil -- renseigner l'id du device % probabilité neige à 12 heures associé, nil si non utilisé + proba_neige_h[36]=nil -- renseigner l'id du device % probabilité neige à 24 heures associé, nil si non utilisé + + local seuil_notification=80 -- pourcentage au delà duquel vous souhaitez être notifié, nil si non utilisé + + -- ======================================================================== + -- Fin Variables à éditer + -- ======================================================================== + local pluie = nil + local neige = nil + local indexArray=0 + --------------------------------------------------------------------------- + --Fonctions + --------------------------------------------------------------------------- + function voir_les_logs (s,debugging) + if (debugging) then + if s ~= nil then + print ("--- --- --- ".. s .." --- --- ---"); + else + print ("aucune valeur affichable"); + end + end + end + --------------------------------------------------------------------------------- + -- Lua-Simple-XML-Parser + --------------------------------------------------------------------------------- + XmlParser = {}; + self = {}; + + function XmlParser:ToXmlString(value) + value = string.gsub(value, "&", "&"); -- '&' -> "&" + value = string.gsub(value, "<", "<"); -- '<' -> "<" + value = string.gsub(value, ">", ">"); -- '>' -> ">" + value = string.gsub(value, "\"", """); -- '"' -> """ + value = string.gsub(value, "([^%w%&%;%p%\t% ])", + function(c) + return string.format("&#x%X;", string.byte(c)) + end); + return value; + end + + function XmlParser:FromXmlString(value) + value = string.gsub(value, "&#x([%x]+)%;", + function(h) + return string.char(tonumber(h, 16)) + end); + value = string.gsub(value, "&#([0-9]+)%;", + function(h) + return string.char(tonumber(h, 10)) + end); + value = string.gsub(value, """, "\""); + value = string.gsub(value, "'", "'"); + value = string.gsub(value, ">", ">"); + value = string.gsub(value, "<", "<"); + value = string.gsub(value, "&", "&"); + return value; + end + + function XmlParser:ParseArgs(node, s) + string.gsub(s, "(%w+)=([\"'])(.-)%2", function(w, _, a) + node:addProperty(w, self:FromXmlString(a)) + end) + end + + function XmlParser:ParseXmlText(xmlText) + local stack = {} + local top = newNode() + table.insert(stack, top) + local ni, c, label, xarg, empty + local i, j = 1, 1 + while true do + ni, j, c, label, xarg, empty = string.find(xmlText, "<(%/?)([%w_:]+)(.-)(%/?)>", i) + if not ni then break end + local text = string.sub(xmlText, i, ni - 1); + if not string.find(text, "^%s*$") then + local lVal = (top:value() or "") .. self:FromXmlString(text) + stack[#stack]:setValue(lVal) + end + if empty == "/" then -- empty element tag + local lNode = newNode(label) + self:ParseArgs(lNode, xarg) + top:addChild(lNode) + elseif c == "" then -- start tag + local lNode = newNode(label) + self:ParseArgs(lNode, xarg) + table.insert(stack, lNode) + top = lNode + else -- end tag + local toclose = table.remove(stack) -- remove top + + top = stack[#stack] + if #stack < 1 then + error("XmlParser: nothing to close with " .. label) + end + if toclose:name() ~= label then + error("XmlParser: trying to close " .. toclose.name .. " with " .. label) + end + top:addChild(toclose) + end + i = j + 1 + end + local text = string.sub(xmlText, i); + if #stack > 1 then + error("XmlParser: unclosed " .. stack[#stack]:name()) + end + return top + end + + function XmlParser:loadFile(xmlFilename, base) + if not base then + base = system.ResourceDirectory + end + + local path = system.pathForFile(xmlFilename, base) + local hFile, err = io.open(path, "r"); + + if hFile and not err then + local xmlText = hFile:read("*a"); -- read file content + io.close(hFile); + return self:ParseXmlText(xmlText), nil; + else + print(err) + return nil + end + end + + function newNode(name) + local node = {} + node.___value = nil + node.___name = name + node.___children = {} + node.___props = {} + + function node:value() return self.___value end + function node:setValue(val) self.___value = val end + function node:name() return self.___name end + function node:setName(name) self.___name = name end + function node:children() return self.___children end + function node:numChildren() return #self.___children end + function node:addChild(child) + if self[child:name()] ~= nil then + if type(self[child:name()].name) == "function" then + local tempTable = {} + table.insert(tempTable, self[child:name()]) + self[child:name()] = tempTable + end + table.insert(self[child:name()], child) + else + self[child:name()] = child + end + table.insert(self.___children, child) + end + + function node:properties() return self.___props end + function node:numProperties() return #self.___props end + function node:addProperty(name, value) + local lName = "@" .. name + if self[lName] ~= nil then + if type(self[lName]) == "string" then + local tempTable = {} + table.insert(tempTable, self[lName]) + self[lName] = tempTable + end + table.insert(self[lName], value) + else + self[lName] = value + end + table.insert(self.___props, { name = name, value = self[name] }) + end + + return node + end + --------------------------------------------------------------------------- + -- Fin Fonctions + --------------------------------------------------------------------------- + commandArray = {} + now=os.date("*t") + + if now.min == 15 + and ((now.hour >= 11 and now.hour <= 13) or (now.hour >= 17 and now.hour <= 20)) + then -- éxécution du script toutes les heures + voir_les_logs("script_time_probabilite_pluie.lua",debugging) + + local fname ="/tmp/weather"..ville.."1.out" + os.execute("wget -q -O " .. fname .. " http://api.wunderground.com/api/"..APIKEY.."/hourly/lang:FR/q/"..countryCode.."/"..ville..".xml") + --voir_les_logs("Fichier local : " ..fname,debugging) + local f = io.open(fname, "r") + + if f == nil then + voir_les_logs("Error opening file '" .. fname .. "'.",debugging) + os.exit(1) + end + + local testXml = f:read("*all") + f:close() + + local parsedXml = XmlParser:ParseXmlText(testXml) + if (parsedXml) then local abr = parsedXml.response.hourly_forecast + + for i in pairs(abr:children()) do + if proba_pluie_h[i] ~= nil then + pluie = tonumber(abr:children()[i]:children()[19]:value()) + voir_les_logs("Probabilite de pluie a ".. i .."h => " .. pluie,debugging) + commandArray[indexArray] = {['UpdateDevice'] = proba_pluie_h[i]..'|0|'.. pluie} + indexArray=indexArray+1 + if seuil_notification ~= nil and pluie > seuil_notification then + commandArray[indexArray] = {['SendNotification'] = 'Alerte : '.. pluie ..' % de probabilité de pluie dans '.. i ..'heure(s)'} + indexArray=indexArray+1 + end + end + if proba_neige_h[i] ~=nil then + neige = tonumber(abr:children()[i]:children()[18]:children()[2]:value()) + voir_les_logs("probabilite de neige a ".. i .."h => " .. neige,debugging) + commandArray[indexArray] = {['UpdateDevice'] = proba_neige_h[i]..'|0|'.. neige} + indexArray=indexArray+1 + if seuil_notification ~= nil and neige > seuil_notification then + commandArray[indexArray] = {['SendNotification'] = 'Alerte : '.. neige ..' % de probabilité de neige dans '.. i ..'heure(s)'} + indexArray=indexArray+1 + end + end + end + end + end -- if now + return commandArray diff --git a/lua/old/script_time_SolarSensor.old b/lua/old/script_time_SolarSensor.old new file mode 100755 index 0000000..1464cd9 --- /dev/null +++ b/lua/old/script_time_SolarSensor.old @@ -0,0 +1,237 @@ +--[[ Virtual Lux sensor and other real-time solar data + + ~/domoticz/scripts/lua/script_time_SolarSensor.lua + + -- http://www.domoticz.com/wiki/Real-time_solar_data_without_any_hardware_sensor_:_azimuth,_Altitude,_Lux_sensor...#Installation_instructions + + -- Autors ---------------------------------------------------------------- + V1.0 - Sébastien Joly - Great original work + V1.1 - Neutrino - Adaptation to Domoticz + V1.2 - Jmleglise - An acceptable approximation of the lux below 1° altitude for Dawn and dusk + translation + several changes to be more userfriendly. + V1.3 - Jmleglise - No update of the Lux data when <=0 to get the sunset and sunrise with lastUpdate + V1.4 - use the API instead of updateDevice to update the data of the virtual sensor to be able of using devicechanged['Lux'] in our scripts. (Due to a bug in Domoticz that doesn't catch the devicechanged event of the virtual sensor) + ]]-- + + -- Variables to customize ------------------------------------------------ + local localhost = '127.0.0.1:81' -- Set your port. (Not the universal IP). + local city = "Redon" -- Your city for Wunderground API + local countryCode = "FR" -- Your country code for Wunderground API + local idxLux ='653' -- Your virtual Lux Device ID + local idxSolarAzimuth ='321' -- Your virtual Azimuth Device ID + local idxSolarAltitude ='322' -- Your virtual Solar Altitude Device ID + local idxUserVarOcta='31' -- Your user variable ID , named octa + local wuAPIkey = "48a08328a93a18a1" -- Your Weather Underground API Key + local latitude = 47.726872 -- your home + local longitude = -2.131937 -- your home + local altitude = 19 -- Your home altitude : run once in debug = 1 to found your altitude in Log and write it here + local WMOID = '07130' --Rennes -- Your nearest SYNOP Station for ogimet. Very important ! http://www.ogimet.com/ + local DEBUG = 0 + if (otherdevices['Debug'] == 'On') then + DEBUG = 1 -- 0 , 1 for domoticz log , 2 for file log + end + -- and customize the URL of api.wunderground around line 104 according to your country. + + -- Below , edit at your own risk ------------------------------------------ + + function leapYear(year) + return year%4==0 and (year%100~=0 or year%400==0) + end + + function split(s, delimiter) + result = {}; + for match in (s..delimiter):gmatch("(.-)"..delimiter) do + table.insert(result, match); + end + return result; + end + + function pow(num, dec) + return num^dec + end + function round(num, dec) + if num == 0 then + return 0 + else + local mult = 10^(dec or 0) + return math.floor(num * mult + 0.5) / mult + end + end + + commandArray = {} + + time = os.date("*t") + if ((time.min % 10)==0) then -- Run every n minutes. Check the wundergroud API limitation before changing this + + json = (loadfile "/opt/domoticz/scripts/lua/JSON.lua")() -- For Linux + --json = (loadfile "D:\\Domoticz\\scripts\\lua\\json.lua")() -- For Windows + + local arbitraryTwilightLux=6.32 -- W/m² egal 800 Lux (the theoritical value is 4.74 but I have more accurate result with 6.32...) + local constantSolarRadiation = 1361 -- Solar Constant W/m² + + if (uservariables['octa'] == nil) then print("Error : Did you create the Uservariable octa ?") end + -- API Wunderground + local url_json = 'curl http://api.wunderground.com/api/'..wuAPIkey..'/conditions/q/'..countryCode..'/'..city..'.json' + print('url_json='..url_json) + --local config=assert(io.popen('curl http://api.wunderground.com/api/'..wuAPIkey..'/conditions/q/'..countryCode..'/'..city..'.json')) + --local location = config:read('*all') + --config:close() + --local jsonLocation = json:decode(location) + --if( DEBUG == 1) then + -- local latitude = jsonLocation.current_observation.display_location.latitude + -- local longitude = jsonLocation.current_observation.display_location.longitude + -- local altitude = jsonLocation.current_observation.display_location.elevation + -- print('Lat: '..latitude..'Long: '..longitude..'Alt: '..altitude) + -- end + --relativePressure = jsonLocation.current_observation.pressure_mb -- if you have an another way to get the Pressure, (local barometer ...) then you may optimize the script and avoid the call to api.wunderground) + ---------------------------------- + print("valeurs"..otherdevices_svalues['BarometreLaGacilly']) + local tab = split(otherdevices_svalues['BarometreLaGacilly'], ";") + print("Pressure="..tostring(tab[4])) + relativePressure = tonumber(tab[4]) + + local year = os.date("%Y") + local numOfDay = os.date("%j") + if leapYear(year) == true then + nbDaysInYear = 366 -- How many days in the year ? + else + nbDaysInYear = 365 + end + + angularSpeed = 360/365.25 + local Declinaison = math.deg(math.asin(0.3978 * math.sin(math.rad(angularSpeed) *(numOfDay - (81 - 2 * math.sin((math.rad(angularSpeed) * (numOfDay - 2)))))))) + timeDecimal = (os.date("!%H") + os.date("!%M") / 60) -- Coordinated Universal Time (UTC) + solarHour = timeDecimal + (4 * longitude / 60 ) -- The solar Hour + hourlyAngle = 15 * ( 12 - solarHour ) -- hourly Angle of the sun + sunAltitude = math.deg(math.asin(math.sin(math.rad(latitude))* math.sin(math.rad(Declinaison)) + math.cos(math.rad(latitude)) * math.cos(math.rad(Declinaison)) * math.cos(math.rad(hourlyAngle))))-- the height of the sun in degree, compared with the horizon + + local azimuth = math.acos((math.sin(math.rad(Declinaison)) - math.sin(math.rad(latitude)) * math.sin(math.rad(sunAltitude))) / (math.cos(math.rad(latitude)) * math.cos(math.rad(sunAltitude) ))) * 180 / math.pi -- deviation of the sun from the North, in degree + local sinAzimuth = (math.cos(math.rad(Declinaison)) * math.sin(math.rad(hourlyAngle))) / math.cos(math.rad(sunAltitude)) + if(sinAzimuth<0) then azimuth=360-azimuth end + sunstrokeDuration = math.deg(2/15 * math.acos(- math.tan(math.rad(latitude)) * math.tan(math.rad(Declinaison)))) -- duration of sunstroke in the day . Not used in this calculation. + RadiationAtm = constantSolarRadiation * (1 +0.034 * math.cos( math.rad( 360 * numOfDay / nbDaysInYear ))) -- Sun radiation (in W/m²) in the entrance of atmosphere. + -- Coefficient of mitigation M + absolutePressure = relativePressure - round((altitude/ 8.3),1) -- hPa + sinusSunAltitude = math.sin(math.rad(sunAltitude)) + + + if (DEBUG == 1) then + print('') + print(os.date("%Y-%m-%d %H:%M:%S", os.time())) + print(city .. ", latitude:" .. latitude .. ", longitude:" .. longitude) + print("Home altitude = " .. tostring(altitude) .. " m") + print("number Of Day = " .. numOfDay) + if nbDaysInYear==366 then + print(year .." is a leap year !") + else + print(year.." is not a leap year") + end + print("Angular Speed = " .. angularSpeed .. " per day") + print("Declinaison = " .. Declinaison .. "°") + print("Universel Coordinated Time (UTC)".. timeDecimal .." H.dd") + print("Solar Hour ".. solarHour .." H.dd") + print("Altitude of the sun = " .. sunAltitude .. "°") + print("Angular hourly = ".. hourlyAngle .. "°") + print("Azimuth of the sun = " .. azimuth .. "°") + print("Duration of the sunstroke of the day = " .. round(sunstrokeDuration,2) .." H.dd") -- not used + print("Radiation max in atmosphere = " .. round(RadiationAtm,2) .. " W/m²") + print("Local relative pressure = " .. relativePressure .. " hPa") + print("Absolute pressure in atmosphere = " .. absolutePressure .. " hPa") + end + local sun = 614 * sinusSunAltitude * 614 * sinusSunAltitude + M0 = math.sqrt(1229 + sun) - 614 * sinusSunAltitude + M = M0 * relativePressure/absolutePressure + print("Coefficient of mitigation M = " .. M .." M0:"..M0) + + -- Get SYNOP message from Ogimet web site + hourUTCminus1 = math.floor(os.date("!%H")-1) + print("hourUTCminus1 = " .. tostring(hourUTCminus1)) + if string.len(hourUTCminus1) == 1 then + hourUTCminus1 = "0" .. hourUTCminus1 + print("hourUTCminus1 = " .. tostring(hourUTCminus1)) + end + UTC = os.date("%Y%m%d").. hourUTCminus1.."00" -- os.date("!%M") + -- if (DEBUG == 1) then + -- local WMOID = jsonLocation.current_observation.display_location.wmo + -- end + + cmd='curl "http://www.ogimet.com/cgi-bin/getsynop?block='..WMOID..'&begin='..UTC..'"' + print(cmd) + local ogimet=assert(io.popen(cmd)) + local synop = ogimet:read('*all') + ogimet:close() + if( DEBUG == 1) then print('ogimet:'..synop) end + + if string.find(synop,"Status: 500") == nil + then + rslt = split(synop,",") + CodeStation = rslt[1] + rslt = split(synop, " "..CodeStation.. " ") + Trame = string.gsub(rslt[2], "=", "") + Trame = CodeStation .." ".. Trame + rslt = split(Trame, " ") + Octa = string.sub(rslt[3], 1, 1) -- 3rd char is the cloud layer. 0=no cloud , 1-8= cloudy from 1 to 8 max , 9 =Fog , / = no data + if Octa == "/" then -- not defined ? take the previous value + Octa = uservariables['octa'] + elseif Octa == "9" then + Octa = 8 + end + else + Octa = uservariables['octa'] + end + + --os.execute('curl "http://127.0.0.1:8081/json.htm?type=command¶m=updateuservariable&idx='..idxUserVarOcta..'&vname=octa&vtype=0&vvalue='..tostring(Octa)..'"') + commandArray[#commandArray + 1] = {['Variable:octa'] = tostring(Octa)} + + Kc=1-0.75*pow(Octa/8,3.4) -- Factor of mitigation for the cloud layer + + if sunAltitude > 1 then -- Below 1° of Altitude , the formulae reach their limit of precision. + directRadiation = RadiationAtm * pow(0.6,M) * sinusSunAltitude + scatteredRadiation = RadiationAtm * (0.271 - 0.294 * pow(0.6,M)) * sinusSunAltitude + totalRadiation = scatteredRadiation + directRadiation + Lux = totalRadiation / 0.0079 -- Radiation in Lux. 1 Lux = 0,0079 W/m² + weightedLux = Lux * Kc -- radiation of the Sun with the cloud layer + elseif sunAltitude <= 1 and sunAltitude >= -7 then -- apply theoretical Lux of twilight + directRadiation = 0 + scatteredRadiation = 0 + arbitraryTwilightLux=arbitraryTwilightLux-(1-sunAltitude)/8*arbitraryTwilightLux + totalRadiation = scatteredRadiation + directRadiation + arbitraryTwilightLux + Lux = totalRadiation / 0.0079 -- Radiation in Lux. 1 Lux = 0,0079 W/m² + weightedLux = Lux * Kc -- radiation of the Sun with the cloud layer + elseif sunAltitude < -7 then -- no management of nautical and astronomical twilight... + directRadiation = 0 + scatteredRadiation = 0 + totalRadiation = 0 + Lux = 0 + weightedLux = 0 -- should be around 3,2 Lux for the nautic twilight. Nevertheless. + end + + if (DEBUG == 1) then + print("Station SYNOP = " .. WMOID) + print( Octa .. " Octa") + print("Kc = " .. Kc) + print("Direct Radiation = ".. round(directRadiation,2) .." W/m²") + print("Scattered Radiation = ".. round(scatteredRadiation,2) .." W/m²") + print("Total radiation = " .. round(totalRadiation,2) .." W/m²") + print("Total Radiation in lux = ".. round(Lux,2).." Lux") + print("and at last, Total weighted lux = ".. round(weightedLux,2).." Lux") + end + + if tonumber(otherdevices_svalues['Lux'])+round(weightedLux,0)>0 -- No update if Lux is already 0. So lastUpdate of the Lux sensor will keep the time when Lux has reached 0. (Kind of timeofday['SunsetInMinutes']) + then +-- commandArray[#commandArray + 1] = {['UpdateDevice'] = idxLux..'|0|'..tostring(round(weightedLux,0))} -- THis form is not recommended. due to limitation of the eventsystem of Domoticz + commandArray[#commandArray + 1]={['OpenURL']="http://"..localhost.."/json.htm?type=command¶m=udevice&idx="..idxLux.."&nvalue=0&svalue="..tostring(round(weightedLux,0)) } + end +-- commandArray[#commandArray + 1] = {['UpdateDevice'] = idxSolarAzimuth..'|0|'..tostring(round(azimuth,0))} + commandArray[#commandArray + 1]={['OpenURL']="http://"..localhost.."/json.htm?type=command¶m=udevice&idx="..idxSolarAzimuth.."&nvalue=0&svalue="..tostring(round(azimuth,0)) } +-- commandArray[#commandArray + 1] = {['UpdateDevice'] = idxSolarAltitude..'|0|'..tostring(round(sunAltitude,0))} + commandArray[#commandArray + 1]={['OpenURL']="http://"..localhost.."/json.htm?type=command¶m=udevice&idx="..idxSolarAltitude.."&nvalue=0&svalue="..tostring(round(sunAltitude,0)) } + + if (DEBUG == 2) then + logDebug=os.date("%Y-%m-%d %H:%M:%S",os.time()) + logDebug=logDebug.." Azimuth:" .. azimuth .. " Height:" .. sunAltitude + logDebug=logDebug.." Octa:" .. Octa.." KC:".. Kc + logDebug=logDebug.." Direct:"..directRadiation.." inDirect:"..scatteredRadiation.." TotalRadiation:"..totalRadiation.." LuxCloud:".. round(weightedLux,2) + os.execute('echo '..logDebug..' >>logSun.txt') -- compatible Linux & Windows + end + end + return commandArray diff --git a/lua/old/script_time_Vigilance.old b/lua/old/script_time_Vigilance.old new file mode 100755 index 0000000..0d51dc3 --- /dev/null +++ b/lua/old/script_time_Vigilance.old @@ -0,0 +1,51 @@ +--curl http://domogeek.entropialux.com/vigilance/56/ + +require "scripts/lua/functions" + +--recupere les minutes +time=os.time() +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) + +commandArray = {} + +-- Function to update a switch +function updateVigilance(zone, idx) + local cmd = "curl -y 1 http://domogeek.entropialux.com/vigilance/"..zone.."/color" + local vac = os.capture(cmd, true) + + local level = 0 + if (vac == "rouge") then level = 4 end + if (vac == "orange") then level = 3 end + if (vac == "jaune") then level = 2 end + if (vac == "vert") then level = 1 end + + if (level >= 3 or (level == 2 and heures == 18)) then + --local html = os.capture("curl \"http://vigilance.meteofrance.com/Bulletin_sans.html?a=dept44&b=2&c=\"", true) + commandArray['SendNotification']='Alerte Vigilance '..vac..'#Attention alerte vigilance '..vac..' sur le '..zone..' \nhttp://vigilance.meteofrance.com/\n#0' + end + + debug("Sunset" .. cmd .. ": "..vac..' Level '..level) + commandArray['UpdateDevice']=idx..'|'..level..'|Niveau de vigilance '..vac..' Departement '..zone +end + + +time = os.date("*t") + +-- local cmd = "curl http://domogeek.entropialux.com/vigilance/56/all" +-- local vac = os.capture(cmd, true) +-- print(vac) +-- Trigger at 0:03 every day +if (time.hour == 0 or time.hour == 6 or time.hour == 12 or time.hour == 18) then + if time.min == 1 then + updateVigilance("56", "185") + end + if time.min == 2 then + updateVigilance("44", "315") + end + if time.min == 3 then + updateVigilance("35", "314") + end +end + +return commandArray diff --git a/lua/old/script_time_angle.old b/lua/old/script_time_angle.old new file mode 100644 index 0000000..cd95a6f --- /dev/null +++ b/lua/old/script_time_angle.old @@ -0,0 +1,146 @@ +require "scripts/lua/functions" + +-- URL du fichier JSON +local url = "http://api.openweathermap.org/data/2.5/weather?q=La%20gacilly,fr&APPID=feba3f4d926db3b358a25ec782bd1c8b&lang=FR&units=metric" + + +time=os.time() +seconds=tonumber(os.date('%S',time)) +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) +jour=tonumber(os.date('%w',time)) +mois=tonumber(os.date('%M',time)) + + +function updateBarometerDevice(deviceId, temperature, humidity, pressure, cloud) + + local svalue = string.format("%.1f;%d;%d;%d;%d;", temperature, humidity, humidity, pressure, cloud) + --local svalue = "TEMP;HUM;HUM_STAT;BAR;BAR_FOR" + url = domoticzURL..'/json.htm?type=command¶m=udevice&idx='..deviceId..'&svalue='..svalue + print(url) + result = os.execute(curl..'"'..url..'" &') + print(result) +end + + +commandArray = {} + +if minutes == 00 and heures == 08 then + if mois == 2 and jour == 01 then + commandArray['SendNotification']='Changement d\'anglet#Passer l\'angle des pannneaux à 60°!' + end + if mois == 3 and jour == 01 then + commandArray['SendNotification']='Changement d\'anglet#Passer l\'angle des pannneaux à 45!' + end + if mois == 4 and jour == 24 then + commandArray['SendNotification']='Changement d\'anglet#Passer l\'angle des pannneaux à 30°!' + end + if mois == 8 and jour == 19 then + commandArray['SendNotification']='Changement d\'anglet#Passer l\'angle des pannneaux à 45!' + end + if mois == 10 and jour == 13 then + commandArray['SendNotification']='Changement d\'anglet#Passer l\'angle des pannneaux à 60°!' + end +end + +if minutes%15 == 0 then + + local cmd = 'curl "'..url..'"' + local jsonContent = os.capture(cmd, true) + -- jsonContent = '{"coord":{"lon":-2.1322,"lat":47.7656},"weather":[{"id":803,"main":"Clouds","description":"nuageux","icon":"04d"}],"base":"stations","main":{"temp":22.33,"feels_like":22.21,"temp_min":21.14,"temp_max":23.77,"pressure":1012,"humidity":61,"sea_level":1012,"grnd_level":1010},"visibility":10000,"wind":{"speed":4.87,"deg":265,"gust":5.72},"clouds":{"all":58},"dt":1686396178,"sys":{"type":2,"id":2007485,"country":"FR","sunrise":1686370227,"sunset":1686427534},"timezone":7200,"id":3009239,"name":"La Gacilly","cod":200}' + + print(cmd) +-- Appel de la fonction pour récupérer le contenu JSON de l'URL + -- local jsonContent = getJSON(url) + json = (loadfile "/opt/domoticz/scripts/lua/JSON.lua")() + + local devices = json:decode(jsonContent) + printTableAsTree(devices) + -- local jsonTable = domoticz.utils.fromJSON(jsonContent) + + + -- Vérification si la récupération du JSON a réussi + if jsonContent then + print("Contenu JSON récupéré avec succès:") + --print(jsonContent) + else + print("Erreur lors de la récupération du JSON") + end + + + -- Conversion du contenu JSON en une table Lua + -- local devices = json.decode(jsonContent) + --local devices = domoticz.utils.fromJSON(jsonContent) +--for k, v in pairs(devices) do + --print(k .. ' '.. v) +--end + pluie_1h = 0 + local main = searchKeyInTable("main", devices['weather']) + print('main='..main) + forecast = 0 + if main == "Clouds" then + nuage = searchKeyInTable("all", devices) + if (tonumber(nuage) > 50) then + forecast = 3 + else + forecast = 2 + end + + print("Nuage " .. nuage) + elseif main == "Rain" then + forecast = 4 + pluie_1h = searchKeyInTable("1h", devices) + elseif main == "Clear" then + nuage = searchKeyInTable("all", devices) + forecast = 1 + end + print("pluie " .. pluie_1h) + + + deviceId = 1159 + -- /json.htm?type=command¶m=udevice&idx=IDX&nvalue=0&svalue=RAINRATE;RAINCOUNTER + local svalue = string.format(";%d", pluie_1h) + url = domoticzURL..'/json.htm?type=command¶m=udevice&idx='..deviceId..'&svalue='..svalue + print(url) + result = os.execute(curl..'"'..url..'" &') + print(result) + + deviceId = 1160 + -- /json.htm?type=command¶m=udevice&idx=IDX&nvalue=0&svalue=RAINRATE;RAINCOUNTER + local svalue = string.format("%d", nuage) + url = domoticzURL..'/json.htm?type=command¶m=udevice&idx='..deviceId..'&svalue='..svalue + print(url) + result = os.execute(curl..'"'..url..'" &') + print(result) + + local temp_min = searchKeyInTable("temp", devices) + local humidity = searchKeyInTable("humidity", devices) + local grnd_level = searchKeyInTable("pressure", devices) + local cloud = searchKeyInTable("all", devices) + + + updateBarometerDevice(1157, temp_min, humidity, grnd_level, forecast) + + + local temp = searchKeyInTable("temp", devices) + local feels_like = searchKeyInTable("feels_like", devices) + local deg = searchKeyInTable("pressure", devices) + + local speed = searchKeyInTable("speed", devices) * 10 + local gust = searchKeyInTable("gust", devices) * 10 + + + deviceId = 1158 + + local svalue = string.format("%d;;%.1f;%.1f;%.1f;%.1f", deg, speed, gust, temp, feels_like) + --local svalue = "TEMP;HUM;HUM_STAT;BAR;BAR_FOR" + url = domoticzURL..'/json.htm?type=command¶m=udevice&idx='..deviceId..'&svalue='..svalue + print(url) + result = os.execute(curl..'"'..url..'" &') + print(result) + +end + + + +return commandArray \ No newline at end of file diff --git a/lua/old/script_time_general.old b/lua/old/script_time_general.old new file mode 100755 index 0000000..31d4fd5 --- /dev/null +++ b/lua/old/script_time_general.old @@ -0,0 +1,245 @@ +require "scripts/lua/functions" + +--recupere les minutes +time=os.time() +seconds=tonumber(os.date('%S',time)) +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) +jour=tonumber(os.date('%w',time)) +mois=tonumber(os.date('%M',time)) + + +--Initialise la commande de retour finale +commandArray={} + +-- ----------------------------------------------------------------------- +-- Test la dernière réception d'un switch et déclenche une alerte +-- Il faut une variable de la forme PILE_nowswitch pour mettre à jour le +-- témoin de notification envoyée +-- ----------------------------------------------------------------------- +function levelBattery( switch ) + if (lastUpdateOfDevice(switch) > 3600 ) then + if (uservariables['Variable:PILE_'..switch] == 'Normal') then + commandArray['SendNotification']='Alerte niveau pile#Attention plus de réception de température depuis '..switch..'#0' + commandArray['Variable:PILE_'..switch]='Plus de réception' + end + else + commandArray['Variable:PILE_'..switch]='Normal' + end +end +-- ----------------------------------------------------------------------- +-- Test le nombre d'erreur dans le log toutes les heures +-- ----------------------------------------------------------------------- +if (minutes == 0) then + local var = os.capture("grep Error /var/log/syslog |wc -l") + --print(var) + + if (tonumber(var) > 0 and tonumber(uservariables['Variable:Erreurs']) == 0) then + commandArray['SendNotification']='Alerte Erreur '..var..'#Attention Il y a des erreurs dans domoticz #0' + + end + commandArray['Variable:Erreurs']=var +end + +-- ----------------------------------------------------------------------- +-- Vérifie le nombre de sequences capturées par motion +-- ----------------------------------------------------------------------- +if (minutes % 10 == 0) then + local f = io.popen("ls /home/pi/motion/ |grep avi| cut -c 1-2 |uniq| wc -l") -- runs command + local l = f:read("*a") -- read output of command + debug("Nombre de detection "..l) + f:close() + commandArray['PhotoMotion']=tostring(l) + commandArray['UpdateDevice']="136|0|"..l +end + +-- ----------------------------------------------------------------------- +--recupere les minutes +-- ----------------------------------------------------------------------- +if (minutes % 10 == 0) then + debug('####### Lancement du check Presence ' ..heures..'h'..minutes) + if (otherdevices['Vacances'] == 'On') then + switchIfNeeded('Presence','Off') + else + --commandArray['Presence']='Off' + ------------------------------------------------------------------------ + if (josdJourChome() or otherdevices['PresenceForcee'] == 'On') then + debug(' Jour Chômé / Presence normale à la maison') + switchIfNeeded('Presence','On') + else + local jourS=josdGetJourSemaine() + debug("jour "..jourS) + if otherdevices['AbsenceFamille'] == 'Off' then + if ((jourS == "mercredi" and (heures >= 13 or (heures == 12 and minutes >= 30))) + or heures >= 17 or heures < 8 + or (heures == 8 and minutes <= 30) + or otherdevices["Zone B"] == 'On' ) then + debug(' Jour non Chômé pas de vacances '..tostring(heures)) + switchIfNeeded('Presence','On') + else + switchIfNeeded('Presence','Off') + end + else + if (((heures == 8 and minutes <= 15) or heures < 8) or heures >= 20 or otherdevices['moi'] == 'On' or otherdevices['Akhenaton'] == 'On') then + switchIfNeeded('Presence','On') + else + switchIfNeeded('Presence','Off') + end + end + end + end +end + +-- -------------------------------------------------------------------------------- +-- Vérification des dernières mises à jour des températures +-- -------------------------------------------------------------------------------- +if (minutes%10== 0) then + levelBattery('Bureau') + levelBattery('ChambreManon') + levelBattery('ChambreTheo') + levelBattery('Chambre') + --levelBattery('ATMEGA_TEMP_1') + levelBattery('TemperatureBarometre') +end + + +-- -------------------------------------------------------------------------------- +-- Function to update a switch +-- -------------------------------------------------------------------------------- +function updateSunset(zone) + local cmd = "curl http://domogeek.entropialux.com/sun/" .. zone .. "/sunset/now" + local vac = os.capture(cmd, true) + debug("Sunset" .. cmd .. ": " .. vac) + commandArray['Variable:Couche']=vac + local cmd = "curl http://domogeek.entropialux.com/sun/" .. zone .. "/sunrise/now" + local vac = os.capture(cmd, true) + debug("Sunrise" .. cmd .. ": " .. vac) + commandArray['Variable:Lever']=vac +end + +-- -------------------------------------------------------------------------------- +-- Trigger at 0:03 every day +-- -------------------------------------------------------------------------------- +if (minutes == 3 and (heures == 0 or heures == 8)) then + updateSunset("redon") +end + +-- ------------------------------------------------------------------- +-- Performance ping +-- ------------------------------------------------------------------- +if (minutes % 10 == 0 ) then + local f = io.popen("ping -c 5 192.168.0.1 2>/dev/null |grep rtt |awk -F = '{print $2}'|awk -F / '{print $2}'") -- runs command + local l = f:read("*a") -- read output of command + debug("##### Perf ping : temps de ping "..l) + f:close() + -- Perf Reseau + commandArray['UpdateDevice']="145|0|"..l +end + +-- ------------------------------------------------------------------------------ +-- Lampes eteinte après 22 heures 30 / 23 heures si pas d'activite depuis 10 minutes +-- ------------------------------------------------------------------------------ +-- Pas de traitement en cas d'alerte fumée +if otherdevices['DétecteurFuméeCuisine'] == "Normal" + -- Pas de traitement si lampe allumée il y a moins d'une heure + and (lastUpdateOfDevice('Lampe_Buffet') > 3600 and otherdevices['Lampe_Buffet'] == 'On') + then + if ((heures >= 23 or (heures == 22 and minutes >= 30)) and (minutes%5==0)) then + + t1 = os.time() + s = uservariables_lastupdate['DerniereDetection'] --otherdevices_lastupdate['Detecteur Salon'] + -- returns a date time like 2013-07-11 17:23:12 + year = string.sub(s, 1, 4) + month = string.sub(s, 6, 7) + day = string.sub(s, 9, 10) + hour = string.sub(s, 12, 13) + minu = string.sub(s, 15, 16) + seconds = string.sub(s, 18, 19) + + t2 = os.time{year=year, month=month, day=day, hour=hour, min=minu, sec=seconds} + difference = (os.difftime (t1, t2)) + debug("Eteindre les lumieres, DerniereDetection="..tostring(difference)) + if (difference > 300 or heures >= 23) then + + switchIfNeeded('Salon_Halogene', 'Off') + switchIfNeeded('Lampe_Buffet', 'Off') + switchIfNeeded('LumiereTele', 'Off') + switchIfNeeded('SonoJasper', 'Off') + end + end +end + + +-- Variation de pression +if minutes%10 == 0 then + + local pressure = otherdevices_svalues['Pression'] + local variationPressure = variationPressure('Barometre',60) + + print("variationPressure="..tostring(variationPressure)..' Pression='..tostring(pressure)) + + +end + +-- --------------------------------- +-- Réglage des consigne temperature +-- --------------------------------- +if minutes%10 == 0 then + + debug('####### Lancement du calcul consigne ' ..heures..'h'..minutes) + + --commandArray['UpdateDevice'] = '214|0|25.00' + + if (otherdevices['Vacances'] == 'On') then + commandArray['UpdateDevice'] = "213|0|16.5" -- Chambre + commandArray['UpdateDevice'] = "211|0|16.5" -- ChambreTheo + commandArray['UpdateDevice'] = "212|0|16.5" -- ChambreManon + commandArray['UpdateDevice'] = "214|0|16.5" -- Bureau + else + --commandArray['Presence']='Off' + ------------------------------------------------------------------------ + if (josdJourChome() or otherdevices['PresenceForcee'] == 'On') then + debug(' Jour Chômé / consigne temperature présence') + commandArray['UpdateDevice'] = "213|0|18" -- Chambre + commandArray['UpdateDevice'] = "211|0|18.5" -- ChambreTheo + commandArray['UpdateDevice'] = "212|0|18.5" -- ChambreManon + commandArray['UpdateDevice'] = "214|0|18" -- Bureau + else + local jourS=josdGetJourSemaine() + debug("jour "..jourS) + if otherdevices['AbsenceFamille'] == 'Off' then + if ((jourS == "mercredi" and (heures >= 13 or (heures == 12 and minutes >= 30))) + or heures >= 17 or heures < 8 + or (heures == 8 and minutes <= 30) + or otherdevices["Zone B"] == 'On' ) then + debug(' Jour non Chômé pas de vacances '..tostring(heures)) + commandArray['UpdateDevice'] = "213|0|18" -- Chambre + commandArray['UpdateDevice'] = "211|0|18.5" -- ChambreTheo + commandArray['UpdateDevice'] = "212|0|18.5" -- ChambreManon + commandArray['UpdateDevice'] = "214|0|18" -- Bureau + + else + commandArray['UpdateDevice'] = "213|0|16.5" -- Chambre + commandArray['UpdateDevice'] = "211|0|16.5" -- ChambreTheo + commandArray['UpdateDevice'] = "212|0|16.5" -- ChambreManon + commandArray['UpdateDevice'] = "214|0|16.5" -- Bureau + end + else + if (((heures == 8 and minutes <= 15) or heures < 8) or heures >= 20 or otherdevices['moi'] == 'On' + or otherdevices['Akhenaton'] == 'On') then + commandArray['UpdateDevice'] = "213|0|18" -- Chambre + commandArray['UpdateDevice'] = "211|0|18.5" -- ChambreTheo + commandArray['UpdateDevice'] = "212|0|18.5" -- ChambreManon + commandArray['UpdateDevice'] = "214|0|18" -- Bureau + else + commandArray['UpdateDevice'] = "213|0|16.5" -- Chambre + commandArray['UpdateDevice'] = "211|0|16.5" -- ChambreTheo + commandArray['UpdateDevice'] = "212|0|16.5" -- ChambreManon + commandArray['UpdateDevice'] = "214|0|16.5" -- Bureau + end + end + end + end +end + +-- return commandArray diff --git a/lua/old/script_time_list.old b/lua/old/script_time_list.old new file mode 100755 index 0000000..f08bae2 --- /dev/null +++ b/lua/old/script_time_list.old @@ -0,0 +1,5 @@ +print('Liste des capteurs : ') +commandArray = {} +for i, v in pairs(otherdevices) do print(i, v) end +return commandArray + diff --git a/lua/old/script_time_livebox.old b/lua/old/script_time_livebox.old new file mode 100755 index 0000000..88565ff --- /dev/null +++ b/lua/old/script_time_livebox.old @@ -0,0 +1,95 @@ +--------------------------------- +-- Script de détection de présence via livebox +-- Auteur : Sopalin +-- Date : 22 Juillet 2016 +-- Nécessite un switch classique +-- source : + +--------------------------------- +require "scripts/lua/functions" + +--recupere les minutes +time=os.time() +seconds=tonumber(os.date('%S',time)) +minutes=tonumber(os.date('%M',time)) + +commandArray={} + +function testActive(name, active) + if active then + --commandArray[name]='On' + switchIfNeeded(name, 'On') + else + switchIfNeeded(name, 'Off') + --commandArray[name]='Off' + end + debug("### Test active Name : "..name.." active "..tostring(active)) +end + + +--time = os.date("*t") +if (minutes % 10 == 7) then + + --import des fontions pour lire le JSON + json = (loadfile "/opt/domoticz/scripts/lua/JSON.lua")() + + --Récupération des informations sur la livebox + --Utilisation d'un script VBS sous windows + --Utilisation d'un script bash pour extraire les données + ---------------------------------------------------------------- + --Lecture des données + + local f = assert(io.open("/tmp/getHosts.txt","r")) + local livebox = f:read('*all') + f:close() + --Décodage ud fichier + local jsonLivebox = json:decode(livebox) + --debug("DEBUG") + --debug(timedifference(otherdevices_lastupdate['Presence Thomas'])) + + --commandArray['Theo']='Off' + --commandArray['Moi']='Off' + --commandArray['Manon']='Off' + devices = jsonLivebox['result']['status'] + --Parcours du fichier pour vérifier la présence d'un téléphone + for result,status in pairs(devices) do + local name = status['hostName'] + debug("Name : "..name.." IP : "..status['ipAddress'].." "..tostring(status['active'])) + + if (name == "Windows-Phone" or name == "Akhesa" or name == "Playstation3") then + --commandArray['Theo']='On' + testActive('Theo', status['active']) + end + if (name == "iPhone-de-Jerome") then + --commandArray['moi']='On' + testActive("Moi", status['active']) + end + if (name == "Akhenaton-1" or name == "Akhenaton") then + testActive("Akhenaton", status['active']) + end + if (name == "Manon" or name == "AcerManon") then + --commandArray['Manon']='On' + testActive("Manon", status['active']) + end + + if (name == "TeleChambre" or name == "AcerManon" + or name == "Volumio" or name == "LibreELEC" or name == "Akhesa" + or name == "SoutiHP" or name == "Hackintosh" + or name == "Akhenaton" + or name == "Domi" or name == "DomiPro" or name == "Octoprint" + or name == "Recovery" or name == "orangepizero" or name == "orangepizero-1") then + testActive(name, status['active']) + end + + if (name == "RadiateurManon" or name == "RadiateurTheo" or name == "RadiateurBureau" + or name == "RadiateurChambre") then + if status['active'] then + -- nothing + else + -- commandArray['SendNotification']='Alerte radiateur '..name..'#Alerte radiateur ne repond pas au ping '..name + end + end + end +end + +return commandArray diff --git a/lua/old/script_time_ping_perf.old b/lua/old/script_time_ping_perf.old new file mode 100755 index 0000000..97279fd --- /dev/null +++ b/lua/old/script_time_ping_perf.old @@ -0,0 +1,36 @@ +require "scripts/lua/functions" + +commandArray = {} + + +--recupere les minutes +time=os.time() +minutes=tonumber(os.date('%M',time)) + +if (minutes % 10 == 0 ) then + local f = io.popen("ping -c 5 192.168.0.1 2>/dev/null |grep rtt |awk -F = '{print $2}'|awk -F / '{print $2}'") -- runs command + local l = f:read("*a") -- read output of command + debug("##### Perf ping : temps de ping "..l) + f:close() + -- Perf Reseau + commandArray['UpdateDevice']="145|0|"..l +end + +if (minutes % 30 == 0 ) then + local f = io.popen("ping -c 4 -n www.free.fr|grep packet|awk -F ' ' '{print $1}'") -- runs command + local l = f:read("*a") -- read output of command + debug("##### Nombre de ping: "..l) + f:close() + if (l == "4") then + debug("##### Internet fonctionne correctement") + switchIfNeeded('Internet','On') + else + debug("##### Internet ne répond pas") + switchIfNeeded('Internet','Off') + end + +end + + +return commandArray + \ No newline at end of file diff --git a/lua/old/script_time_soleil.lua b/lua/old/script_time_soleil.lua new file mode 100755 index 0000000..4b4e84a --- /dev/null +++ b/lua/old/script_time_soleil.lua @@ -0,0 +1,30 @@ +--------------------------------- +-- Script de collecte de quelques indicateurs solaire +-- Auteur : Sébastien Joly +-- Adapté pour Domoticz par Neutrino +-- Date : 29 août 2015 +-- Eléments de calculs : +-- http://www.plevenon-meteo.info/technique/theorie/enso/ensoleillement.html +-- http://herve.silve.pagesperso-orange.fr/solaire.htm +-- http://www.domotique-info.fr/2015/09/ou-est-le-soleil-pour-votre-homecenter-2/ +--------------------------------- +require "scripts/lua/functions" + + +commandArray = {} + +time = os.date("*t") + +local idxLux="320" + +if ((time.min % 5)==0) then + if (timeofday['Nighttime']) then + --il fait nuit + LuxPondere = 0 + --mise a jour du dispositif + commandArray[1] = {['UpdateDevice'] = idxLux..'|0|' .. tostring(LuxPondere)} + else + os.execute("lua /opt/domoticz/scripts/lua/soleil.lua "..uservariables['octa'].." &") + end +end +return commandArray diff --git a/lua/old/script_time_tele.old b/lua/old/script_time_tele.old new file mode 100755 index 0000000..c252118 --- /dev/null +++ b/lua/old/script_time_tele.old @@ -0,0 +1,89 @@ +require "scripts/lua/functions" + +--Initialise la commande de retour finale +commandArray={} + + + +--Prefixe pour les sorties de log +prefixe="(PING) " + +--recupere les minutes +time=os.time() +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) + +if (heures >= 22 and (minutes % 10 == 0)) then + + -- ------------------------------ + --Tableau des périphérique"pinguer" + -- Key = adresse ip pinguer + -- Value = périphérique virtueswitcher + -- ------------------------------ + local ping={} + ping['192.168.0.17']='TeleChambre' + ping['akhenaton']='Akhenaton' + + AuMoinsUnPing=false + -- ------------------------------ + --pour chaque entree du tableau + -- ------------------------------ + for ip, switch in pairs(ping) do + + --Le Ping ! : -c1 = Un seul ping , -w1 délai d'une seconde d'attente de réponse + ping_success=os.execute('ping -c1 -w1 '..ip) + + -- ------------------------------ + --Si le ping a répondu + -- ------------------------------ + if ping_success then + AuMoinsUnPing=true + + debug(prefixe.."ping success "..switch) + + -- ------------------------------ + --si le switch etait sur off on l'allume + -- ------------------------------ + switchIfNeeded(switch, 'On') + --if(otherdevices[switch]=='Off') then + -- commandArray[switch]='On' + --end + else + + -- ------------------------------ + --Si pas de réponse + -- ------------------------------ + debug(prefixe.."ping sans reponse "..switch) + -- ------------------------------ + --si le switch etait sur oN on l'eteint + -- ------------------------------ + switchIfNeeded(switch, 'Off') + --if(otherdevices[switch]=='On') then + -- commandArray[switch]='Off' + --end + end + end + + if AuMoinsUnPing then + else + -- ------------------------------ + -- Extinction halogene + -- ------------------------------ + debug("Tout le monde est couché") + -- if(otherdevices["Salon_Halogene"]=='On') + + switchIfNeeded("Salon_Halogene",'Off') + switchIfNeeded("LumiereTele",'Off') + switchIfNeeded("Lampe_Buffet",'Off') + -- end + if(otherdevices["Volet droit"]=='On') then + debug("Attention le volet droit est ouvert") + end + if(otherdevices["Volet gauche"]=='On') then + debug("Attention le volet gauche est ouvert") + end + end + +end +return commandArray + diff --git a/lua/old/script_time_vmc.old b/lua/old/script_time_vmc.old new file mode 100755 index 0000000..c20dd64 --- /dev/null +++ b/lua/old/script_time_vmc.old @@ -0,0 +1,601 @@ +-- http://easydomoticz.com/forum/viewtopic.php?f=17&t=2869&hilit=vmc + +require "scripts/lua/fonctions2" + +commandArray = {} + +--recupere les minutes +time=os.time() +minutes=tonumber(os.date('%M',time)) +--jour=tonumber(os.date('%w',time)) +heures=tonumber(os.date('%H',time)) + +if minutes%10 == 6 then + +INTERVAL_MESURE = 2 -- Nombre d'intervals de mesure entre deux cycles d'analyse de l'humidité (en nombre de cycles = nombre de minutes) +SEUIL_DECLENCHEMENT_VMC = 2 -- Augmentation en % au-delà de laquelle on déclenche la GV de la VMC +NbCycles_Max_GV_VMC = 5 -- Nombre de cycles maximum durant lequel la GV de la VMC peut rester ON + -- à partir du moment où il n'y a plus d'augmentation de l'humidité entre deux mesures +Anticipation_Arret= 1 -- l'arrêt de la grande vitesse se fera à l'humidité avant déclenchement de la GV plus cette valeur + -- ce qui permet d'anticiper l'arrêt de la grande vitesse avant d'atteindre la valeur initiale + +NOM_INTERRUPTEUR_PILOTAGE_VMC = 'VMC' +NOM_INTERRUPTEUR_OnOff_VMC = 'VMC-OnOff' +NOM_INTERRUPTEUR_GV_VMC = 'VMC-GV' +NOM_CAPTEUR_HUMIDITE1 = 'TemperatureSDB' +NOM_CAPTEUR_HUMIDITE2 = 'TemperatureCuisine' +NOM_INTERRUPTEUR_DEBUG = 'Debug' +NOM_INTERRUPTEUR_TEST = 'Test-GV-SDB' +--NOM_CAPTEUR_VIRTUEL_HYGRO_MOYENNE= 'Hygro_Maison_Moyenne' +VALEUR_TEST_HUMIDITE1 = 'VMC_TST_HUM_SDB1' -- valeur de test pour l'umidité positionné dans les variables domoticz +VALEUR_TEST_HUMIDITE2 = 'VMC_TST_HUM_SDB2' -- valeur de test pour l'umidité positionné dans les variables domoticz + +-- --------------------------------------------------------------------- +-- Récupération de paramètres de Domoticz passés par les interrupteurs +-- --------------------------------------------------------------------- + if(otherdevices[NOM_INTERRUPTEUR_DEBUG]=='On') then -- Si le mode debug est activé dans Domoticz (inter debug sur on) + MODE_DEBUGG= true + else + MODE_DEBUGG= false + end + + if(otherdevices[NOM_INTERRUPTEUR_TEST]=='On') then -- Si le mode test est activé dans Domoticz (inter Test sur on) + MODE_TEST=true + else + MODE_TEST=false + end + + -- MODE_TEST=true + + if MODE_DEBUGG== true then + print(' ') + print('>>>>>>>>>>>>>> Script de controle de la VMC v1.0 <<<<<<<<<<<<<<<<<<<<<') + end + +-- ---------------------------------------------------------------------------------- +-- --Récupération de toutes les variables Domoticz servant au script et remise à 0 -- +-- ---------------------------------------------------------------------------------- + VMC_VAR_Compteur_Cycles = tonumber(uservariables['VMC_VAR_Compteur_Cycles']) -- compteur de cycles + VMC_VAR_Histo_Hum1_SDB1 = tonumber(uservariables['VMC_VAR_Histo_Hum1_SDB1']) -- mesure la plus récente SDB1 + VMC_VAR_Histo_Hum1_SDB2 = tonumber(uservariables['VMC_VAR_Histo_Hum1_SDB2']) -- mesure la plus récente SDB2 + VMC_VAR_Histo_Hum2_SDB1 = tonumber(uservariables['VMC_VAR_Histo_Hum2_SDB1']) -- mesure la plus ancienne SDB1 + VMC_VAR_Histo_Hum2_SDB2 = tonumber(uservariables['VMC_VAR_Histo_Hum2_SDB2']) -- mesure la plus ancienne SDB2 + + VMC_VAR_Cible_Hum_GV_Off_SDB1 = tonumber(uservariables['VMC_VAR_Cible_Hum_GV_Off_SDB1']) -- Cible à atteindre pour arrêter la deshumidification SDB1 lorsqu'elle est active + VMC_VAR_Cible_Hum_GV_Off_SDB2 = tonumber(uservariables['VMC_VAR_Cible_Hum_GV_Off_SDB2']) -- Cible à atteindre pour arrêter la deshumidification SDB2 lorsqu'elle est active + + VMC_VAR_TimerSecuriteArret_SDB1 = tonumber(uservariables['VMC_VAR_TimerSecuriteArret_SDB1']) -- Nb de cycles restants avant l'arrête automatique de sécurité de la SDB1 + VMC_VAR_TimerSecuriteArret_SDB2 = tonumber(uservariables['VMC_VAR_TimerSecuriteArret_SDB2']) -- Nb de cycles restants avant l'arrête automatique de sécurité de la SDB2 + + VMC_VAR_Deshumidification_On_SDB1 = tonumber(uservariables['VMC_VAR_Deshumidification_On_SDB1']) -- Vaut 1 si la deshumidification est en cours dans la SDB1, 0 sinon + VMC_VAR_Deshumidification_On_SDB2 = tonumber(uservariables['VMC_VAR_Deshumidification_On_SDB2']) -- Vaut 1 si la deshumidification est en cours dans la SDB2, 0 sinon + + Cible_Humidite_SDB1 = 0 -- Variable servant à calculer la cible d'humidité lorsuqe la déshumidification s'active pour la SDB1 + Cible_Humidite_SDB2 = 0 -- Variable servant à calculer la cible d'humidité lorsuqe la déshumidification s'active pour la SDB2 + + Humidite_Actuelle_EXT = tonumber(otherdevices_humidity["BarometreLaGacilly"]) + Temperature_Actuelle_EXt = tonumber(otherdevices_temperature["BarometreLaGacilly"]) + + -- ******************************************************************** + -- SI L'UTILISATEUR A ACTIVé LA VMC DE MANIERE MANUELLE ON N'EXECUTE -- + -- PAS LE SCRIPT ET ON POSITIONNE LA VMC A LA BONNNE VALEUR + -- ******************************************************************** + Etat_Pilotage_VMC = tonumber(otherdevices_svalues[NOM_INTERRUPTEUR_PILOTAGE_VMC]) -- récupération de l'état de l'inter 4 positions de pilotage de la VMC + print('Etat_Pilotage_VMC='..tostring(Etat_Pilotage_VMC)) + + if Etat_Pilotage_VMC < 30 then -- Si inter sur mode différent d'automatique (qui vaut 30) + if Etat_Pilotage_VMC == 0 then -- Si inter sur VMC Off + print('VMC arretee manuellement via l interrupteur. Sortie du script') + commandArray[NOM_INTERRUPTEUR_OnOff_VMC] = 'Off' + commandArray[NOM_INTERRUPTEUR_GV_VMC] = 'Off' + end + if Etat_Pilotage_VMC == 10 then -- Si inter sur VMC petite vitesse + print('VMC positionnee en marche / petite vitesse via l interrupteur. Sortie du script') + commandArray[NOM_INTERRUPTEUR_OnOff_VMC] = 'On' + commandArray[NOM_INTERRUPTEUR_GV_VMC] = 'Off' + end + if Etat_Pilotage_VMC == 20 then -- si inter sur VMC grande vitesse + print('VMC positionnee en marche / grande vitesse via l interrupteur. Sortie du script') + commandArray[NOM_INTERRUPTEUR_OnOff_VMC] = 'On' + commandArray[NOM_INTERRUPTEUR_GV_VMC] = 'On' + end + + print('NOM_CAPTEUR_HUMIDITE1 '..tostring(tonumber(otherdevices_humidity[NOM_CAPTEUR_HUMIDITE1]))) + + -- On n'est plus en mode automatique donc on sort du script après l'avoir remis à 0 (réinitialisation de toutes les variables) + commandArray['Variable:VMC_VAR_Compteur_Cycles'] = '0' + commandArray['Variable:VMC_VAR_Histo_Hum2_SDB1'] = tostring(math.floor(tonumber(otherdevices_humidity[NOM_CAPTEUR_HUMIDITE1]))) + commandArray['Variable:VMC_VAR_Histo_Hum1_SDB1'] = tostring(math.floor(tonumber(otherdevices_humidity[NOM_CAPTEUR_HUMIDITE1]))) + commandArray['Variable:VMC_VAR_Cible_Hum_GV_Off_SDB1'] = '0' + commandArray['Variable:VMC_VAR_TimerSecuriteArret_SDB1'] = '0' + commandArray['Variable:VMC_VAR_Deshumidification_On_SDB1'] = '0' + commandArray['Variable:VMC_VAR_Histo_Hum2_SDB2'] = tostring(math.floor(tonumber(otherdevices_humidity[NOM_CAPTEUR_HUMIDITE2]))) + commandArray['Variable:VMC_VAR_Histo_Hum1_SDB2'] = tostring(math.floor(tonumber(otherdevices_humidity[NOM_CAPTEUR_HUMIDITE2]))) + commandArray['Variable:VMC_VAR_Cible_Hum_GV_Off_SDB2'] = '0' + commandArray['Variable:VMC_VAR_TimerSecuriteArret_SDB2'] = '0' + commandArray['Variable:VMC_VAR_Deshumidification_On_SDB2'] = '0' + return commandArray + end + + print('mode automatique') + +-- ************************************** +-- Recuperation des valeurs d'humidite +-- ************************************** + if (MODE_TEST) then + -- Si on est en mode test, on prends les valeurs fixées dans les variables DOMOTICZ + Humidite_Actuelle_SDB1 = tonumber(uservariables['VMC_TST_HUM_SDB1']) + Humidite_Actuelle_SDB2 = tonumber(uservariables['VMC_TST_HUM_SDB2']) + Hygro_Moyenne_Maison = tonumber(uservariables['VMC_TST_HUM_MOYENNE_MAISON']) + else + -- Si on est en mode normal, on prends les valeurs remontées par les capteurs + Humidite_Actuelle_SDB1 = otherdevices_humidity[NOM_CAPTEUR_HUMIDITE1] + Humidite_Actuelle_SDB2 = otherdevices_humidity[NOM_CAPTEUR_HUMIDITE2] + Humidite_Actuelle_CELLIER = otherdevices_humidity["TemperatureCellier"] + + Hygro_Moyenne_Maison = math.max(Humidite_Actuelle_SDB1, Humidite_Actuelle_CELLIER) -- otherdevices_humidity[NOM_CAPTEUR_VIRTUEL_HYGRO_MOYENNE] + end + + print('Hygro_Moyenne_Maison='..tostring(Hygro_Moyenne_Maison)) + +-- L'humidité maximum acceptable dans la salle de bain est le maximum de la valeur moyenne humidité +-- en cours dans la maison et de la valeur fixées +-- Cette humidité max permet de maintenir la VMC en petite vitesse même si l'humidité de la salle de +-- bain est redescendue après un pic + Maximum_Humidite_Acceptable_SDB = math.max(tonumber(uservariables['Hygro_Max_SDB']), Hygro_Moyenne_Maison) + +-- ****************************************************************************** +-- Sortie du script si les valeurs d'humidité récupérées ne sont pas exploitables +-- ******************************************************************************* + if (Humidite_Actuelle_SDB1 == 0 or Humidite_Actuelle_SDB1 == nil) then + print('Pas de signal du capteur ' .. NOM_CAPTEUR_HUMIDITE1 .. '. Sortie du script') + return commandArray + end + if (Humidite_Actuelle_SDB2 == 0 or Humidite_Actuelle_SDB2 == nil) then + print('Pas de signal du capteur ' .. NOM_CAPTEUR_HUMIDITE2 .. '. Sortie du script') + return commandArray + end + if (Hygro_Moyenne_Maison== 0 or Hygro_Moyenne_Maison== nil) then + print('Pas de signal du capteur virtuel d humidite moyenne de la maison, Sortie du script') + return commandArray + end + + print('Les capteurs sont ok ') + +-- ************************************************************************************ +-- Le script est executé toutes les minutes, on augmente la valeur du compteur de cycle +-- ************************************************************************************ + VMC_VAR_Compteur_Cycles = VMC_VAR_Compteur_Cycles + 1 + +-- *************************************************************************************************** +-- On commence par traiter l'humidité globale de la maison pour savoir si la VMC doit être activée ou non +-- *************************************************************************************************** + local humidite_ext = humiditeAbsolue(Temperature_Actuelle_EXt, Humidite_Actuelle_EXT) + local humidite_sdb = humiditeAbsolue(tonumber(otherdevices_temperature["TemperatureSDB"]), + tonumber(otherdevices_humidity["TemperatureSDB"])) + + + if humidite_ext > humidite_sdb then + print("L'humidité extérieure est trop élevée. Arret VMC") + + commandArray[NOM_INTERRUPTEUR_OnOff_VMC] = 'Off' + commandArray[NOM_INTERRUPTEUR_GV_VMC] = 'Off' + return commandArray + else + if Hygro_Moyenne_Maison > uservariables['Hygro_Max_Maison'] then + Hygro_Max_Depassee = 1 -- L'humidité de la maison est trop importante on active la VMC + commandArray[NOM_INTERRUPTEUR_OnOff_VMC] = 'On' + else -- L'humidité de la maison est correcte + Hygro_Max_Depassee = 0 + if VMC_VAR_Deshumidification_On_SDB1 == 0 and VMC_VAR_Deshumidification_On_SDB2 == 0 then + if Humidite_Actuelle_SDB1 <= Maximum_Humidite_Acceptable_SDB and + Humidite_Actuelle_SDB2 <= Maximum_Humidite_Acceptable_SDB + then + commandArray[NOM_INTERRUPTEUR_OnOff_VMC] = 'Off' -- on arrête la VMC si aucune des salles de bains n'est utilisée et que l'humidité des salles de bain est acceptable + else + commandArray[NOM_INTERRUPTEUR_OnOff_VMC] = 'On' -- on allume la VMC si aucune des salles de bains n'est utilisée mais que l'humidité des salles de bain n'est pas acceptable + end + end + end + end + + -- ----------------------------------- + -- Affichage des infos en mode debug + -- ----------------------------------- + if MODE_DEBUGG== true then + print('***************') + print('ETAT ACTUEL : ') + print('***************') + if Hygro_Moyenne_Maison <= uservariables['Hygro_Max_Maison'] + and VMC_VAR_Deshumidification_On_SDB1 ==0 + and VMC_VAR_Deshumidification_On_SDB2 == 0 + then + if Humidite_Actuelle_SDB1 <= Maximum_Humidite_Acceptable_SDB and Humidite_Actuelle_SDB2 <= Maximum_Humidite_Acceptable_SDB then + print('[Hygro Maison] - Hygrometrie correcte (' .. Hygro_Moyenne_Maison .. '% vs ' .. uservariables['Hygro_Max_Maison'] ..'% max) et aucune salle de bain en cours d utilisation, desactivation de la vmc') + else + print('[Hygro Maison] - Hygrometrie correcte (' .. Hygro_Moyenne_Maison .. '% vs ' .. uservariables['Hygro_Max_Maison'] ..'% max), aucune salle de bain en cours d utilisation mais humidite SDB toujours trop elevee, VMC laissee active en petite vitesse') + end + else + if VMC_VAR_Deshumidification_On_SDB1 ==0 and VMC_VAR_Deshumidification_On_SDB2 == 0 then + print('[Hygro Maison] - Hygrometrie incorrect (' .. Hygro_Moyenne_Maison .. '% vs ' .. uservariables['Hygro_Max_Maison'] ..'% max), maintien de la VMC meme si aucune salle de bain en cours d utilisation') + end + end + if VMC_VAR_Deshumidification_On_SDB1 == 0 then + print('[' .. NOM_CAPTEUR_HUMIDITE1 .. '] - Deshumidification OFF - actuelle : ' .. Humidite_Actuelle_SDB1 .. '% / Precedente : ' .. VMC_VAR_Histo_Hum1_SDB1 .. '% / Cycle -2 : ' .. VMC_VAR_Histo_Hum2_SDB1 .. '%') + else + print('[' .. NOM_CAPTEUR_HUMIDITE1 .. '] - Deshumidification ON - actuelle : ' .. Humidite_Actuelle_SDB1 .. '% / Precedente : ' .. VMC_VAR_Histo_Hum1_SDB1 ..'% / Cycle -2 : ' .. VMC_VAR_Histo_Hum2_SDB1 .. '% / Cible arret : ' .. VMC_VAR_Cible_Hum_GV_Off_SDB1 .. '% / arret de securite dans ' .. VMC_VAR_TimerSecuriteArret_SDB1 .. ' cycle(s)') + end + if VMC_VAR_Deshumidification_On_SDB2 == 0 then + print('[' .. NOM_CAPTEUR_HUMIDITE2 .. '] - Deshumidification OFF - actuelle : ' .. Humidite_Actuelle_SDB2 .. '% / Precedente : ' .. VMC_VAR_Histo_Hum1_SDB2 .. '% / Cycle -2 : ' .. VMC_VAR_Histo_Hum2_SDB2 .. '%') + else + print('[' .. NOM_CAPTEUR_HUMIDITE2 .. '] - Deshumidification ON - actuelle : ' .. Humidite_Actuelle_SDB2 .. '% / Precedente : ' .. VMC_VAR_Histo_Hum1_SDB2 ..'% / Cycle -2 : ' .. VMC_VAR_Histo_Hum2_SDB2 .. '% / Cible arret : ' .. VMC_VAR_Cible_Hum_GV_Off_SDB2 .. '% / arret de securite dans ' .. VMC_VAR_TimerSecuriteArret_SDB2 .. ' cycle(s)') + end + end + +if (VMC_VAR_Compteur_Cycles >= INTERVAL_MESURE) then + -- ************************************************************************************* + -- Si le nombre de cycles a atteint l'interval de mesure fixé on commence l'analyse pour + -- identifier les besoins d'activation ou désactivation de la grande vitesse de la VMC + -- ************************************************************************************* + VMC_VAR_Compteur_Cycles = 0 -- remise à 0 du compteur de cycle + + -- ----------------------------------- + -- Affichage des infos en mode debug + -- ----------------------------------- + if MODE_DEBUGG== true then + print(' ') + print('***************') + print('ANALYSE : ') + print('***************') + print('Nombre de cycles atteint (' .. VMC_VAR_Compteur_Cycles .. '/' .. INTERVAL_MESURE .. '), realisation des tests pour adapter la vitesse VMC') + end + + -- *************************************************************************** + -- Initialisation des historiques s'ils ne contiennent aucune information. On + -- positionne alors dans les deux historiques les valeurs d'hulidité actuelles + -- *************************************************************************** + if (VMC_VAR_Histo_Hum1_SDB1 == 0) then + -- Initialisation des valeurs historiques + VMC_VAR_Histo_Hum1_SDB1 = Humidite_Actuelle_SDB1 + VMC_VAR_Histo_Hum2_SDB1 = Humidite_Actuelle_SDB1 + end + if (VMC_VAR_Histo_Hum1_SDB2 == 0) then + -- Initialisation des valeurs historiques + VMC_VAR_Histo_Hum1_SDB2 = Humidite_Actuelle_SDB2 + VMC_VAR_Histo_Hum2_SDB2 = Humidite_Actuelle_SDB2 + end + + -- ******************************************************************** + -- Calcul des écarts maximum d'humidité constatés dans chacune des SDB + -- ******************************************************************** + Ecart_Max_Humidite_SDB1 = Humidite_Actuelle_SDB1 - math.min(VMC_VAR_Histo_Hum2_SDB1, VMC_VAR_Histo_Hum1_SDB1) + Ecart_Max_Humidite_SDB2 = Humidite_Actuelle_SDB2 - math.min(VMC_VAR_Histo_Hum2_SDB2, VMC_VAR_Histo_Hum1_SDB2) + + -- ----------------------------------- + -- Affichage des infos en mode debug + -- ----------------------------------- + if MODE_DEBUGG== true then + print('[' .. NOM_CAPTEUR_HUMIDITE1 .. '] - Ecart max d humidite constate sur les dernieres periodes : ' .. Ecart_Max_Humidite_SDB1) + print('[' .. NOM_CAPTEUR_HUMIDITE2 .. '] - Ecart max d humidite constate sur les dernieres periodes : ' .. Ecart_Max_Humidite_SDB2) + end + + -- ******************************************************************************************************** + -- Identification de la cible humidité à atteindre si la grande vitesse de la VMC est activée. Il s'agira + -- de redescendre à la plus basse des valeurs d'humidité de l'historique + un % défini dans "Anticipation_Arret" + -- ******************************************************************************************************** + Cible_Humidite_SDB1 = math.min(VMC_VAR_Histo_Hum2_SDB1, VMC_VAR_Histo_Hum1_SDB1) + Anticipation_Arret + Cible_Humidite_SDB2 = math.min(VMC_VAR_Histo_Hum2_SDB2, VMC_VAR_Histo_Hum1_SDB2) + Anticipation_Arret + + -- ***************************************************************************** + -- Sauvegarde dans l'historique des mesures précédentes et de la mesure actuelle + -- ***************************************************************************** + VMC_VAR_Histo_Hum2_SDB1 = VMC_VAR_Histo_Hum1_SDB1 -- L'historique le plus ancien reçoit l'historique plus récent de l'humidité + VMC_VAR_Histo_Hum2_SDB2 = VMC_VAR_Histo_Hum1_SDB2 + VMC_VAR_Histo_Hum1_SDB1 = Humidite_Actuelle_SDB1 -- L'historique plus récent reçoit la valeur actuelle d'humidité + VMC_VAR_Histo_Hum1_SDB2 = Humidite_Actuelle_SDB2 + + -- ******************************************************************************************************** + -- Remise à 0 des indicateurs précisant s'il y a eu un déclenchement de la GV pour une des SDB lors + -- de l'execution du script en cours. Pour l'instant aucune mise en route n'a été décidée/effectuée + -- ******************************************************************************************************** + Declenchement_SDB1 = 0 + Declenchement_SDB2 = 0 + + -- ***************************************************************************** + -- Si le ventilateur est off alors qu'un des deux programmes est en route, on + -- force l'arrêt des programmes de déshumidification (arrêt manuel extérieur) + -- ***************************************************************************** + if (otherdevices[NOM_INTERRUPTEUR_GV_VMC]=='Off') + and (VMC_VAR_Deshumidification_On_SDB1 == 1 or VMC_VAR_Deshumidification_On_SDB2 ==1) + then + VMC_VAR_Deshumidification_On_SDB1 = 0 + VMC_VAR_Deshumidification_On_SDB2 = 0 + end + + -- ***************************************************************************************** + -- Si la VMC n'est pas en grande vitesse ou si une des deux SDB n'est pas en grande vitesse + -- on identifie s'il est nécessaire de mettre en route la marche forcée pour une des SDBs + -- ***************************************************************************************** + if otherdevices[NOM_INTERRUPTEUR_GV_VMC]=='Off' + or VMC_VAR_Deshumidification_On_SDB1 == 0 + or VMC_VAR_Deshumidification_On_SDB2 == 0 + then + + -- ************************************************************************** + -- Identification du besoin éventuel de déclenchement de la VMC pour la SDB1 + -- Besoin identifié si humidité > au seuil de déclenchement et que le programme + -- de déshumidification n'est pas déjà activé pour cette SDB + -- ************************************************************************** + if Ecart_Max_Humidite_SDB1 >= SEUIL_DECLENCHEMENT_VMC and VMC_VAR_Deshumidification_On_SDB1 == 0 then + commandArray[NOM_INTERRUPTEUR_GV_VMC] = 'On' + commandArray[NOM_INTERRUPTEUR_OnOff_VMC] = 'On' + VMC_VAR_Deshumidification_On_SDB1 = 1 + VMC_VAR_Cible_Hum_GV_Off_SDB1 = Cible_Humidite_SDB1 + VMC_VAR_TimerSecuriteArret_SDB1 = NbCycles_Max_GV_VMC + Declenchement_SDB1 = 1 + + -- ----------------------------------- + -- Affichage des infos en mode debug + -- ----------------------------------- + if MODE_DEBUGG== true then + print('[' .. NOM_CAPTEUR_HUMIDITE1 .. '] - Augmentation soudaine de l humidite. Activation de la VMC en grande vitesse. Ecart d humidite observe: ' .. Ecart_Max_Humidite_SDB1) + print('[' .. NOM_CAPTEUR_HUMIDITE1 .. '] - Cible a atteindre pour l extinction du ventilateur : ' ..VMC_VAR_Cible_Hum_GV_Off_SDB1) + end + + else + if MODE_DEBUGG== true and Ecart_Max_Humidite_SDB2 >= SEUIL_DECLENCHEMENT_VMC and VMC_VAR_Deshumidification_On_SDB1 == 0 then + print('[' .. NOM_CAPTEUR_HUMIDITE1 .. '] - Ecart non significatif, pas de mise en route du programme de deshumidification') + end + end + + -- ************************************************************************** + -- Identification du besoin éventuel de déclenchement de la VMC pour la SDB2 + -- Besoin identifié si humidité > au seuil de déclenchement et que le programme + -- de déshumidification n'est pas déjà activé pour cette SDB + -- ************************************************************************** + if Ecart_Max_Humidite_SDB2 >= SEUIL_DECLENCHEMENT_VMC and VMC_VAR_Deshumidification_On_SDB2 == 0 then + commandArray[NOM_INTERRUPTEUR_GV_VMC] = 'On' + commandArray[NOM_INTERRUPTEUR_OnOff_VMC] = 'On' + VMC_VAR_Deshumidification_On_SDB2 = 1 + VMC_VAR_Cible_Hum_GV_Off_SDB2 = Cible_Humidite_SDB2 + VMC_VAR_TimerSecuriteArret_SDB2 = NbCycles_Max_GV_VMC + Declenchement_SDB2 = 1 + + -- ----------------------------------- + -- Affichage des infos en mode debug + -- ----------------------------------- + if MODE_DEBUGG== true then + print('[' .. NOM_CAPTEUR_HUMIDITE2 .. '] - Augmentation soudaine de l humidite. Activation de la VMC en grande vitesse. Ecart d humidite observe: ' .. Ecart_Max_Humidite_SDB2) + print('[' .. NOM_CAPTEUR_HUMIDITE2 .. '] - Cible a atteindre pour l extinction du ventilateur : ' ..VMC_VAR_Cible_Hum_GV_Off_SDB2) + end + else + if MODE_DEBUGG== true and Ecart_Max_Humidite_SDB1 >= SEUIL_DECLENCHEMENT_VMC and VMC_VAR_Deshumidification_On_SDB2 == 0 then + print('[' .. NOM_CAPTEUR_HUMIDITE2 .. '] - Ecart non significatif, pas de mise en route du programme de deshumidification') + end + end + end + + -- ----------------------------------- + -- Affichage des infos en mode debug + -- ----------------------------------- + if Ecart_Max_Humidite_SDB1 < SEUIL_DECLENCHEMENT_VMC + and Ecart_Max_Humidite_SDB2 < SEUIL_DECLENCHEMENT_VMC + then + if MODE_DEBUGG== true then + print('Ecarts non significatif sur les deux SDB, pas de mise en route du programme de deshumidification') + end + end + + -- ***************************************************************************************** + -- Si la VMC est en grande vitesse après l'analyse du besoin effectuée ci-dessus + -- ***************************************************************************************** + if (otherdevices[NOM_INTERRUPTEUR_GV_VMC]=='On') or VMC_VAR_Deshumidification_On_SDB1 == 1 or VMC_VAR_Deshumidification_On_SDB2 == 1 then + if (VMC_VAR_TimerSecuriteArret_SDB1 > 0) then -- Si le déshumidification est en courspour la SDB1 on diminue + VMC_VAR_TimerSecuriteArret_SDB1 = VMC_VAR_TimerSecuriteArret_SDB1 - 1 -- la valeur du timer de sécurité pour l'arrêt automatique + end + if (VMC_VAR_TimerSecuriteArret_SDB2 > 0) then -- Si le déshumidification est en courspour la SDB2 on diminue + VMC_VAR_TimerSecuriteArret_SDB2 = VMC_VAR_TimerSecuriteArret_SDB2 - 1 -- la valeur du timer de sécurité pour l'arrêt automatique + end + end + + -- ***************************************************************************************** + -- Si la VMC est en grande vitesse pour la SDB1 et que l'humidité continue d'augmenter + -- ***************************************************************************************** + if (VMC_VAR_Deshumidification_On_SDB1 == 1) then + if (Ecart_Max_Humidite_SDB1 >= SEUIL_DECLENCHEMENT_VMC and Declenchement_SDB1 == 0) then + -- S'il y a encore un écart d'humidité constaté sur la dernière période (augmentation humidité toujours en cours) et qu'il n'y a pas + -- eu de déclenchement dans ce cycle, on considère qu'on n'a pas encore atteint l'humidité max et on remet à 0 la VMC_VAR_TimerSecuriteArret_SDB1 + VMC_VAR_TimerSecuriteArret_SDB1 = NbCycles_Max_GV_VMC + + if MODE_DEBUGG== true then + print('[' .. NOM_CAPTEUR_HUMIDITE1 .. '] - L humidite est toujours en augmentation, remise a 0 de la Securite Arret. Ecart constate sur la derniere periode : ' .. Ecart_Max_Humidite_SDB1) + end + + end + end + + -- ***************************************************************************************** + -- Si la VMC est en grande vitesse pour la SDB2 et que l'humidité continue d'augmenter + -- ***************************************************************************************** + if (VMC_VAR_Deshumidification_On_SDB2 == 1) then + if (Ecart_Max_Humidite_SDB2 >= SEUIL_DECLENCHEMENT_VMC and Declenchement_SDB2 == 0) then + -- S'il y a encore un écart d'humidité constaté sur la dernière période (augmentation humidité toujours en cours) et qu'il n'y a pas + -- eu de déclenchement dans ce cycle, on considère qu'on n'a pas encore atteint l'humidité max et on remet à 0 la VMC_VAR_TimerSecuriteArret_SDB2 + VMC_VAR_TimerSecuriteArret_SDB2 = NbCycles_Max_GV_VMC + + if MODE_DEBUGG== true then + print('[' .. NOM_CAPTEUR_HUMIDITE2 .. '] - L humidite est toujours en augmentation, remise a 0 de la Securite Arret. Ecart constate sur la derniere periode : ' .. Ecart_Max_Humidite_SDB2) + end + end + end + + -- ************************************************************************************************************* + -- Analyse pour identifier si la grande vitesse peut être arrêtée si elle a été activée auparavant. + -- Si les Timers de sécurité sont atteints ou que l'humidité est redescendu pour les deux SDB on + -- arrête la grande vitesse et on regarde si on peut arrêter complètement la VMC (si l'humidité globale est Ok) + -- ************************************************************************************************************* + if (VMC_VAR_TimerSecuriteArret_SDB1 == 0 or Humidite_Actuelle_SDB1 <= VMC_VAR_Cible_Hum_GV_Off_SDB1) and (VMC_VAR_TimerSecuriteArret_SDB2 == 0 or Humidite_Actuelle_SDB2 <= VMC_VAR_Cible_Hum_GV_Off_SDB2) then + commandArray[NOM_INTERRUPTEUR_GV_VMC] = 'Off' + if Hygro_Max_Depassee == 0 then -- Si l'humidité maximum globale de la maison n'est pas atteinte + if Humidite_Actuelle_SDB1<= uservariables['Hygro_Max_SDB'] and Humidite_Actuelle_SDB2<= uservariables['Hygro_Max_SDB'] then -- Si l'humidité des deux SDB est inférieure à l'humidité maximum acceptable dans une SDB + commandArray[NOM_INTERRUPTEUR_OnOff_VMC] = 'Off' -- on arrête complètement la VMC + if MODE_DEBUGG== true then + print('[Hygro Maison] - Hygrometrie correcte (' .. Hygro_Moyenne_Maison .. '% vs ' .. uservariables['Hygro_Max_Maison'] ..'% max) et aucune salle de bain en cours d utilisation, desactivation de la vmc') + end + else + -- sinon (hygro maison Ok, mais humidité d'une des deux SDB dépasse la valeur maximum acceptable), on active la VMC en petite vitesse + commandArray[NOM_INTERRUPTEUR_OnOff_VMC] = 'On' + if MODE_DEBUGG== true then + print('[Hygro Maison] - Hygrometrie correcte (' .. Hygro_Moyenne_Maison .. '% vs ' .. uservariables['Hygro_Max_Maison'] ..'% max), aucune salle de bain en cours d utilisation mais humidite SDB toujours trop elevee, VMC laissee active en petite vitesse') + end + end + end + end + + -- ************************************************************************************************************* + -- Analyse pour identifier s'il faut arrêter la grande vitesse suite à atteinte du timer de sécurité sur la SDB1 + -- ************************************************************************************************************* + if (VMC_VAR_TimerSecuriteArret_SDB1 == 0 and Humidite_Actuelle_SDB1 > VMC_VAR_Cible_Hum_GV_Off_SDB1 and VMC_VAR_Deshumidification_On_SDB1 == 1) then + -- ----------------------------------- + -- Affichage des infos en mode debug + -- ----------------------------------- + if MODE_DEBUGG== true then + print('[' .. NOM_CAPTEUR_HUMIDITE1 .. '] - L humidite n est pas redescendue a sa valeur initiale (avant activation de la grande vitesse) mais le TimeOut de securite pour l arret est atteint. Arret de la grande vitesse de la VMC pour ' .. NOM_CAPTEUR_HUMIDITE1) + end + -- Si on a atteint le timer de sécurité on réinitialise l'historique avec la valeur d'hulidité actuelle ainsi que les variables de la SDB1 + VMC_VAR_Histo_Hum2_SDB1 = VMC_VAR_Histo_Hum1_SDB1 + VMC_VAR_Deshumidification_On_SDB1 = 0 + VMC_VAR_Cible_Hum_GV_Off_SDB1 = 0 + VMC_VAR_TimerSecuriteArret_SDB1 = 0 + VMC_VAR_Deshumidification_On_SDB1 = 0 + end + + -- ************************************************************************************************************* + -- Analyse pour identifier s'il faut arrêter la grande vitesse suite à retour à au taux d'humidité initial sur la SDB1 + -- ************************************************************************************************************* + if (VMC_VAR_TimerSecuriteArret_SDB1 > 0 and Humidite_Actuelle_SDB1 <= VMC_VAR_Cible_Hum_GV_Off_SDB1 and VMC_VAR_Deshumidification_On_SDB1 == 1) then + -- ----------------------------------- + -- Affichage des infos en mode debug + -- ----------------------------------- + if MODE_DEBUGG== true then + print('[' .. NOM_CAPTEUR_HUMIDITE1 .. '] - L humidite est redescendue a une valeur proche de sa valeur initiale ('.. VMC_VAR_Cible_Hum_GV_Off_SDB1 ..'%). Arret de la grande vitesse de la VMC pour ' .. NOM_CAPTEUR_HUMIDITE1) + end + -- On réinitialise l'historique avec la valeur d'hulidité actuelle ainsi que les variables de la SDB1 + VMC_VAR_Histo_Hum2_SDB1 = VMC_VAR_Histo_Hum1_SDB1 + VMC_VAR_Deshumidification_On_SDB1 = 0 + VMC_VAR_Cible_Hum_GV_Off_SDB1 = 0 + VMC_VAR_TimerSecuriteArret_SDB1 = 0 + VMC_VAR_Deshumidification_On_SDB1 = 0 + end + + + -- ************************************************************************************************************* + -- Analyse pour identifier s'il faut arrêter la grande vitesse suite à atteinte du timer de sécurité sur la SDB2 + -- ************************************************************************************************************* + if (VMC_VAR_TimerSecuriteArret_SDB2 == 0 and Humidite_Actuelle_SDB2 > VMC_VAR_Cible_Hum_GV_Off_SDB2 and VMC_VAR_Deshumidification_On_SDB2 == 1) then + -- ----------------------------------- + -- Affichage des infos en mode debug + -- ----------------------------------- + if MODE_DEBUGG== true then + print('[' .. NOM_CAPTEUR_HUMIDITE2 .. '] - L humidite n est pas redescendue a sa valeur initiale (avant activation de la grande vitesse) mais le TimeOut de securite pour l arret est atteint. Arret de la grande vitesse de la VMC pour ' .. NOM_CAPTEUR_HUMIDITE2) + end + -- Si on a atteint le timer de sécurité on réinitialise l'historique avec la valeur d'hulidité actuelle ainsi que les variables de la SDB2 + VMC_VAR_Deshumidification_On_SDB2 = 0 + VMC_VAR_Cible_Hum_GV_Off_SDB2 = 0 + VMC_VAR_TimerSecuriteArret_SDB2 = 0 + VMC_VAR_Deshumidification_On_SDB2 = 0 + VMC_VAR_Histo_Hum2_SDB2 = VMC_VAR_Histo_Hum1_SDB2 + end + + -- ************************************************************************************************************* + -- Analyse pour identifier s'il faut arrêter la grande vitesse suite à retour à au taux d'humidité initial sur la SDB2 + -- ************************************************************************************************************* + if (VMC_VAR_TimerSecuriteArret_SDB2 > 0 and Humidite_Actuelle_SDB2 <= VMC_VAR_Cible_Hum_GV_Off_SDB2 and VMC_VAR_Deshumidification_On_SDB2 == 1) then + -- ----------------------------------- + -- Affichage des infos en mode debug + -- ----------------------------------- + if MODE_DEBUGG== true then + print('[' .. NOM_CAPTEUR_HUMIDITE2 .. '] - L humidite est redescendue a une valeur proche de sa valeur initiale ('.. VMC_VAR_Cible_Hum_GV_Off_SDB2 ..'%). Arret de la grande vitesse de la VMC pour ' .. NOM_CAPTEUR_HUMIDITE2) + end + -- On réinitialise l'historique avec la valeur d'hulidité actuelle ainsi que les variables de la SDB2 + VMC_VAR_Deshumidification_On_SDB2 = 0 + VMC_VAR_Cible_Hum_GV_Off_SDB2 = 0 + VMC_VAR_TimerSecuriteArret_SDB2 = 0 + VMC_VAR_Deshumidification_On_SDB2 = 0 + VMC_VAR_Histo_Hum2_SDB2 = VMC_VAR_Histo_Hum1_SDB2 + end + + -- ----------------------------------- + -- Affichage des infos en mode debug + -- ----------------------------------- + if MODE_DEBUGG== true then + if (Humidite_Actuelle_SDB1 > VMC_VAR_Cible_Hum_GV_Off_SDB1 and VMC_VAR_TimerSecuriteArret_SDB1 > 0 and Declenchement_SDB1 == 0) then + print('[' .. NOM_CAPTEUR_HUMIDITE1 .. '] - Deshumidification toujours en cours, humidite actuelle = ' .. Humidite_Actuelle_SDB1.. '% ,cible = ' .. VMC_VAR_Cible_Hum_GV_Off_SDB1 .. '% ,TimerSecurite= ' .. VMC_VAR_TimerSecuriteArret_SDB1) + end + if (Humidite_Actuelle_SDB2 > VMC_VAR_Cible_Hum_GV_Off_SDB2 and VMC_VAR_TimerSecuriteArret_SDB2 > 0 and Declenchement_SDB2 == 0) then + print('[' .. NOM_CAPTEUR_HUMIDITE2 .. '] - Deshumidification toujours en cours, humidite actuelle = ' .. Humidite_Actuelle_SDB2.. '% ,cible = ' .. VMC_VAR_Cible_Hum_GV_Off_SDB2 .. '% ,TimerSecurite= ' .. VMC_VAR_TimerSecuriteArret_SDB2) + end + end +else + -- ----------------------------------- + -- Affichage des infos en mode debug + -- ----------------------------------- + if MODE_DEBUGG== true then + print('Nombre de cycles avant la realisation des tests d adaptation de la vitesse VMC non atteint (' .. VMC_VAR_Compteur_Cycles .. '/' .. INTERVAL_MESURE .. ')') + end +end + +-- ******************************************************* +-- Si la VMC est arrêtée on arrête aussi la grande vitesse +-- ******************************************************* +if commandArray[NOM_INTERRUPTEUR_OnOff_VMC] == 'Off' then + commandArray[NOM_INTERRUPTEUR_GV_VMC] = 'Off' +end + +if MODE_DEBUGG== true then + print(' ') + print('***************') + print('ETAT EN SORTIE : ') + print('***************') + + if VMC_VAR_Deshumidification_On_SDB1 == 0 then + print('[' .. NOM_CAPTEUR_HUMIDITE1 .. '] - Deshumidification OFF - actuelle : ' .. Humidite_Actuelle_SDB1 .. '% / Precedente : ' .. VMC_VAR_Histo_Hum1_SDB1 .. '% / Cycle -2 : ' .. VMC_VAR_Histo_Hum2_SDB1 .. '%') + else + print('[' .. NOM_CAPTEUR_HUMIDITE1 .. '] - Deshumidification ON - actuelle : ' .. Humidite_Actuelle_SDB1 .. '% / Precedente : ' .. VMC_VAR_Histo_Hum1_SDB1 ..'% / Cycle -2 : ' .. VMC_VAR_Histo_Hum2_SDB1 .. '% / Cible arret : ' .. VMC_VAR_Cible_Hum_GV_Off_SDB1 .. '% / arret de securite dans ' .. VMC_VAR_TimerSecuriteArret_SDB1 .. ' cycle(s)') + end + + if VMC_VAR_Deshumidification_On_SDB2 == 0 then + print('[' .. NOM_CAPTEUR_HUMIDITE2 .. '] - Deshumidification OFF - actuelle : ' .. Humidite_Actuelle_SDB2 .. '% / Precedente : ' .. VMC_VAR_Histo_Hum1_SDB2 .. '% / Cycle -2 : ' .. VMC_VAR_Histo_Hum2_SDB2 .. '%') + else + print('[' .. NOM_CAPTEUR_HUMIDITE2 .. '] - Deshumidification ON - actuelle : ' .. Humidite_Actuelle_SDB2 .. '% / Precedente : ' .. VMC_VAR_Histo_Hum1_SDB2 ..'% / Cycle -2 : ' .. VMC_VAR_Histo_Hum2_SDB2 .. '% / Cible arret : ' .. VMC_VAR_Cible_Hum_GV_Off_SDB2 .. '% / arret de securite dans ' .. VMC_VAR_TimerSecuriteArret_SDB2 .. ' cycle(s)') + end + + if Hygro_Moyenne_Maison <= uservariables['Hygro_Max_Maison'] and VMC_VAR_Deshumidification_On_SDB1 ==0 and VMC_VAR_Deshumidification_On_SDB2 == 0 then + if Humidite_Actuelle_SDB1 <= Maximum_Humidite_Acceptable_SDB and Humidite_Actuelle_SDB2 <= Maximum_Humidite_Acceptable_SDB then + print('[Hygro Maison] - Hygrometrie correcte (' .. Hygro_Moyenne_Maison .. '% vs ' .. uservariables['Hygro_Max_Maison'] ..'% max) et aucune salle de bain en cours d utilisation, VMC desactivee') + else + print('[Hygro Maison] - Hygrometrie correcte (' .. Hygro_Moyenne_Maison .. '% vs ' .. uservariables['Hygro_Max_Maison'] ..'% max), aucune salle de bain en cours d utilisation mais humidite SDB toujours trop elevee, VMC laissee active en petite vitesse') + end + else + if Hygro_Moyenne_Maison > uservariables['Hygro_Max_Maison'] then + print('[Hygro Maison] - Hygrometrie incorrecte (' .. Hygro_Moyenne_Maison .. '% vs ' .. uservariables['Hygro_Max_Maison'] ..'% max), VMC activee') + end + end +end + +-- Sauvegarde des variables +commandArray['Variable:VMC_VAR_Compteur_Cycles'] = tostring(VMC_VAR_Compteur_Cycles) +commandArray['Variable:VMC_VAR_Histo_Hum2_SDB1'] = tostring(math.floor(tonumber(VMC_VAR_Histo_Hum2_SDB1))) +commandArray['Variable:VMC_VAR_Histo_Hum1_SDB1'] = tostring(math.floor(tonumber(VMC_VAR_Histo_Hum1_SDB1))) +commandArray['Variable:VMC_VAR_Cible_Hum_GV_Off_SDB1'] = tostring(VMC_VAR_Cible_Hum_GV_Off_SDB1) +commandArray['Variable:VMC_VAR_TimerSecuriteArret_SDB1'] = tostring(VMC_VAR_TimerSecuriteArret_SDB1) +commandArray['Variable:VMC_VAR_Deshumidification_On_SDB1'] = tostring(VMC_VAR_Deshumidification_On_SDB1) + +commandArray['Variable:VMC_VAR_Histo_Hum2_SDB2'] = tostring(math.floor(tonumber(VMC_VAR_Histo_Hum2_SDB2))) +commandArray['Variable:VMC_VAR_Histo_Hum1_SDB2'] = tostring(math.floor(tonumber(VMC_VAR_Histo_Hum1_SDB2))) +commandArray['Variable:VMC_VAR_Cible_Hum_GV_Off_SDB2'] = tostring(VMC_VAR_Cible_Hum_GV_Off_SDB2) +commandArray['Variable:VMC_VAR_TimerSecuriteArret_SDB2'] = tostring(VMC_VAR_TimerSecuriteArret_SDB2) +commandArray['Variable:VMC_VAR_Deshumidification_On_SDB2'] = tostring(VMC_VAR_Deshumidification_On_SDB2) + +end +return commandArray diff --git a/lua/old/script_time_volets.old b/lua/old/script_time_volets.old new file mode 100755 index 0000000..d67f061 --- /dev/null +++ b/lua/old/script_time_volets.old @@ -0,0 +1,205 @@ +require "scripts/lua/functions" + +commandArray = {} + +local HEURE_DEB = 9 +local HEURE_FIN = 17 +local TEMP_MAX = 24 +local TEMP_MAX_2 = 28 + + +--recupere les minutes +time=os.time() +minutes=tonumber(os.date('%M',time)) +--jour=tonumber(os.date('%w',time)) +heures=tonumber(os.date('%H',time)) + +local saison = uservariables["Saison"] +local jourS = josdGetJourSemaine() + +-- ------------------------------------------------------------------- +-- Verification des volets ouverts si température trop basse +-- ------------------------------------------------------------------- +if (minutes == 0 or minutes == 30 ) then + + debug('########## Lancement du check fermeture velux du grenier ' ..heures..'h'..minutes) + + tab = getValuesInTab('BarometreLaGacilly') + + local tmp = tonumber(tab[1]) + + debug('########## Lancement du check fermeture velux du grenier ' ..heures..'h'..minutes..' tmp='..tostring(tmp)) + + if (tmp < 14.0 and (otherdevices['Velux droit'] == 'Open' or otherdevices['Velux gauche'] == 'Open')) then + commandArray['notification']="Volet ouvert#Un des volets du grenier est reste ouvert #0" + end +end + +-- ----------------------- +-- Fermeture volet central +-- ----------------------- +if minutes%30 == 0 + and (saison ~= "Ete") + and (heures >= 22) -- or uservariables['Dark'] == "True") +then +debug('------------------------------------------------------') + debug(' Test fermeture volet Central '..otherdevices['VoletPorteSalon']) + debug('------------------------------------------------------') + if (otherdevices['VoletPorteSalon'] ~= 'Closed') then + commandArray['VoletPorteSalon']='On' + end +end + +-- --------------------------------------------------------------------------------------- +-- Fermeture des volets en fonction de la temperature exterieure Pas l'ETE +-- --------------------------------------------------------------------------------------- +--print("DARK=="..tostring(uservariables['Dark'] == "True")) +if minutes%9 == 0 and + (saison ~= "Ete") + and (otherdevices['VoletCuisine'] == 'Open' or otherdevices['VoletSalonTele'] == 'Open') + and (heures >= 18 or + ( + heures >= 17 and ( + uservariables['Dark'] == "True") + or (tonumber(otherdevices['Lux']) < tonumber(uservariables["LuxMini"])) + ) + ) +then + debug('------------------------------------------------------') + debug(' Test fermeture volet ') + debug('------------------------------------------------------') + + debug('####### Comparaison heure vs Couche du soleil ========>'..uservariables["Heure"].." "..uservariables["Couche"]) + debug('####### Lancement du check test ' ..heures..'h'..minutes..' volet cuisine '..otherdevices['BarometreLaGacilly']..' svalues='..otherdevices_svalues['BarometreLaGacilly']..' VoletCuisine='..otherdevices['VoletCuisine']) + tmp = otherdevices_svalues['BarometreLaGacilly'] + tab = split(tmp, ";") + debug("######### Check fermeture : temperature lue par BarometreLaGacilly "..tab[1]) + + temp = tonumber(tab[1]) + if ( + ( + ( + (temp < 6.0 and whenDark() <= 30) + or (temp < 8 and whenDark() <= 15) + or (temp < 10 and whenDark() <= 0) + ) + ) + or ( + uservariables['Dark'] == "True" + ) + ) + then + debug("######### Dans temperature") + if (otherdevices['VoletCuisine'] == 'Open') then -- or (minutes % 10 == 0 and heures <=20) ) then + commandArray['VoletCuisine']='On' + end + if (otherdevices['VoletSalonTele'] == 'Open') then -- or (minutes % 10 == 0 and heures <=20)) then + commandArray['VoletSalonTele']='On' + end + else + debug("############ PAS DANS LE IF") + end + +end + +-- ------------------------------------------------------------------------------ +-- Ouverture des volets en fonction de la temperature exterieure Hiver et Automne +-- ------------------------------------------------------------------------------ +if minutes%5 == 0 + and heures <= HEURE_DEB + and ((heures >= 9 and josdJourChome()) or (heures > 6 and not josdJourChome())) + and (saison == "Hiver" or saison == "Automne") + and (greater2(uservariables["Heure"],uservariables["Lever"], - 30)) -- heures >= 20 + and (otherdevices['VoletCuisine'] == 'Closed' + or otherdevices['VoletSalonTele'] == 'Closed' + or otherdevices['VoletPorteSalon'] == 'Closed' + ) +then + debug('------------------------------------------------------') + debug(' Test ouverture volet ') + debug('------------------------------------------------------') + + debug('####### Comparaison heure vs Lever du soleil ========>'..uservariables["Heure"].. + " "..uservariables["Lever"]) + debug('####### Lancement du check test ' ..heures..'h'..minutes..' volet cuisine ' + ..otherdevices['BarometreLaGacilly']..' svalues='..otherdevices_svalues['BarometreLaGacilly']..' VoletCuisine='..otherdevices['VoletCuisine']) + + tmp = otherdevices_svalues['BarometreLaGacilly'] + tab = split(tmp, ";") + debug("######### Check Ouverture : temperature lue par BarometreLaGacilly "..tab[1]) + + temp = tonumber(tab[1]) + if (temp > 12.0 or (heures >=9 and minutes >= 30)) then + if (otherdevices['VoletCuisine'] == 'Closed' or (minutes % 10 == 0 and heures == 9)) then + commandArray['VoletCuisine']='Off' + end + if (otherdevices['VoletSalonTele'] == 'Closed' or (minutes % 10 == 0 and heures == 9)) then + commandArray['VoletSalonTele']='Off' + end + if (otherdevices['VoletPorteSalon'] == 'Closed' or (minutes % 10 == 0 and heures == 9)) then + commandArray['VoletPorteSalon']='Off' + end + end +end + +-- ------------------------------------------------------------------------------ +-- fermeture des volets en fonction de la temperature interieure en ete +-- ------------------------------------------------------------------------------ +if minutes%5 == 0 --and uservariables['Dark'] == "False" +and (heures > HEURE_DEB and heures <= HEURE_FIN) +--and (saison == "ete") +--and (greater(uservariables["Heure"] , uservariables["Lever"])) -- heures >= 20 +--and (otherdevices['VoletCuisine'] == 'Open' or otherdevices['VoletSalonTele'] == 'Open' or otherdevices['VoletPorteSalon'] == 'Open') +then + debug('------------------------------------------------------') + debug(' Test fermeture volet Ete') + debug('------------------------------------------------------') + + debug('####### Lancement du check test ' ..heures..'h'..minutes..' volet cuisine '..otherdevices['BarometreLaGacilly']..' svalues='..otherdevices_svalues['BarometreLaGacilly']..' VoletCuisine='..otherdevices['VoletCuisine']) + local val + local val2 + val, val2 = otherdevices_svalues['BarometreLaGacilly']:match("([^;]+);([^;]+)") + + debug("BarometreLaGacilly"..otherdevices["BarometreLaGacilly"]..val.." "..val2..otherdevices['VoletCuisine'].." "..otherdevices['VoletSalonTele'].." "..otherdevices['VoletPorteSalon']) + + local temp = tonumber(val) + + if temp >= TEMP_MAX and (otherdevices['VoletCuisine'] == 'Open' and otherdevices['VoletSalonTele'] == 'Open' + and otherdevices['VoletPorteSalon'] == 'Open') then + debug("fermeture volets : temp élevée") + if temp >= TEMP_MAX_2 then + os.execute("/opt/domoticz/scripts/volets2.sh On &") + else + os.execute("/opt/domoticz/scripts/volets.sh On &") + end + end +end + + +-- ------------------------------------------------------------------------------ +-- Réouverture après la vague de chaleur ETE +-- ------------------------------------------------------------------------------ +if minutes%5 == 0 +and (heures > HEURE_FIN and heures <= 19) +and (saison == "ete" ) +then + local val + local val2 + val, val2 = otherdevices_svalues['BarometreLaGacilly']:match("([^;]+);([^;]+)") + + print("BarometreLaGacilly"..otherdevices["BarometreLaGacilly"].." "..val.." "..val2..otherdevices['VoletCuisine'].." "..otherdevices['VoletSalonTele'].." "..otherdevices['VoletPorteSalon']) + + local temp = tonumber(val) + + if ((temp <= 24 or (temp <= TEMP_MAX and heures >= 18)) + and (otherdevices['VoletCuisine'] == 'Closed' and + otherdevices['VoletSalonTele'] == 'Closed' and + otherdevices['VoletPorteSalon'] == 'Closed')) + then + debug("Ouverture volets : temp en baisse") + os.execute("/opt/domoticz/scripts/volets.sh Off &") + end + +end + +return commandArray diff --git a/lua/old/soleil.lua b/lua/old/soleil.lua new file mode 100755 index 0000000..0c9aba4 --- /dev/null +++ b/lua/old/soleil.lua @@ -0,0 +1,238 @@ +--Variables à éditer-------------- +local Ville = "pws:ILAGACIL2" --Ville de référence +local idxLux = '320' --Capteur virtuel de Luminosité +local idxOcta = '5' -- idx de la variable Utilisateur +local wuAPIkey = "48a08328a93a18a1" +local DEBUG = 'OUI' + +--import des fontions pour lire le JSON +json = (loadfile "/opt/domoticz/scripts/lua/JSON.lua")() + +-- Fonction déterminant si année bissextile +function AnneeBissextile(annee) + return annee%4==0 and (annee%100~=0 or annee%400==0) +end + +--------------------------------- +-- Fonction spliter +function split(s, delimiter) + result = {}; + for match in (s..delimiter):gmatch("(.-)"..delimiter) do + table.insert(result, match); + end + return result; +end + + +--------------------------------- +-- Fonction Arrondir +function arrondir(num, dec) + if num == 0 then + return 0 + else + local mult = 10^(dec or 0) + return math.floor(num * mult + 0.5) / mult + end +end + +--------------------------------- +-- Procedure principale +--------------------------------- + +--------------------------------- +-- Meteo API Wunderground +local config=assert(io.popen('curl http://api.wunderground.com/api/'..wuAPIkey..'/conditions/q/FR/'..Ville..'.json')) +local location = config:read('*all') +config:close() +local jsonLocation = json:decode(location) + +local Latitude = jsonLocation.current_observation.display_location.latitude +local Longitude = jsonLocation.current_observation.display_location.longitude +local Altitude = jsonLocation.current_observation.display_location.elevation +PressionRelative = jsonLocation.current_observation.pressure_mb + +---------------------------------- +local An = os.date("%Y") +local NiemeJourDeLAnnee = os.date("%j") +--------------------------------- +DateHeure = os.date("%Y-%m-%d %H:%M:%S", os.time()) +-- Début debug +if( DEBUG == 'OUI') then + print("=====================================") + print(os.date("%Y-%m-%d %H:%M:%S", os.time())) + print(Ville .. ", " .. Latitude .. ", " .. Longitude) + print("Altitude = " .. tostring(Altitude) .. " m") + print("NiemeJourDeLAnnee = " .. NiemeJourDeLAnnee) +end +--------------------------------- +--calcul de l'année bissextile +if AnneeBissextile(An) == true then + if( DEBUG == 'OUI') then + print( An .. " est bissextile.") + end + JourDansLAnnee = 366 +else + if( DEBUG == 'OUI') then + print( An .. " n'est pas bissextile.") + end + JourDansLAnnee = 365 +end +--------------------------------- +-- Vitesse angulaire = Combien de degrés par jour +VitesseAngulaire = 360/365.25 ----JourDansLAnnee -- ou approximativement 365.25 +if( DEBUG == 'OUI') then + print("Vitesse angulaire = " .. VitesseAngulaire .. " par jour") +end +--------------------------------- +-- Formule Declinaison = ArcSin(0,3978 x Sin(Va x (j - (81 - 2 x Sin(Va� x (j - 2)))))) +local Declinaison = math.deg(math.asin(0.3978 * math.sin(math.rad(VitesseAngulaire) *(NiemeJourDeLAnnee - (81 - 2 * math.sin((math.rad(VitesseAngulaire) * (NiemeJourDeLAnnee - 2)))))))) +if( DEBUG == 'OUI') then + print("La déclinaison = " .. Declinaison .. "°") +end +--------------------------------- +-- Temps universel décimal (UTC) +TempsDecimal = (os.date("!%H") + os.date("!%M") / 60) +if( DEBUG == 'OUI') then + print("Temps universel decimal (UTC)".. TempsDecimal .." H.dd") +end +--------------------------------- +-- Temps solaire +HeureSolaire = TempsDecimal + (4 * Longitude / 60 ) +if( DEBUG == 'OUI') then + print("Temps solaire ".. HeureSolaire .." H.dd") +end +--------------------------------- +-- Angle horaire du soleil +AngleHoraire = 15 * ( 12 - HeureSolaire ) +if( DEBUG == 'OUI') then + print("Angle Horaire = ".. AngleHoraire .. "°") +end +--------------------------------- +-- La hauteur du soleil (Elévation ou altitude) +HauteurSoleil = math.deg(math.asin(math.sin(math.rad(Latitude))* math.sin(math.rad(Declinaison)) + math.cos(math.rad(Latitude)) * math.cos(math.rad(Declinaison)) * math.cos(math.rad(AngleHoraire)))) +if( DEBUG == 'OUI') then + print("Hauteur du soleil = " .. HauteurSoleil .. "°") +end +local Azimut = math.acos((math.sin(math.rad(Declinaison)) - math.sin(math.rad(Latitude)) * math.sin(math.rad(HauteurSoleil))) / (math.cos(math.rad(Latitude)) * math.cos(math.rad(HauteurSoleil) ))) * 180 / math.pi +local SinAzimut = (math.cos(math.rad(Declinaison)) * math.sin(math.rad(AngleHoraire))) / math.cos(math.rad(HauteurSoleil)) +if(SinAzimut<0) then + Azimut=360-Azimut +end +if( DEBUG == 'OUI') then + print("Azimut du soleil = " .. Azimut .. "°") +end +--------------------------------- +-- La durée d'insolation journalière - non stockée en VG +DureeInsolation = math.deg(2/15 * math.acos(- math.tan(math.rad(Latitude)) * math.tan(math.rad(Declinaison)))) +DureeInsolation = arrondir(DureeInsolation,2) +if( DEBUG == 'OUI') then + print("La durée d'insolation journalière = " .. DureeInsolation .." H.dd") +end +--------------------------------- +-- Constantes Solaire +ConstanteRatiationSolaire = 1361 -- W/m² +ConstanteRadiationLux = 200000 -- Lux +--------------------------------- +-- Rayonnement solaire (en W/m²) présent à l'entrée de l'atmosphère. +RadiationAtm = ConstanteRatiationSolaire * (1 +0.034 * math.cos( math.rad( 360 * NiemeJourDeLAnnee / JourDansLAnnee ))) +if( DEBUG == 'OUI') then + print("Radiation max en atmosphère = " .. arrondir(RadiationAtm,2) .. " W/m²") +end +--------------------------------- +-- Coefficient d'attenuation M +PressionAbsolue = PressionRelative - arrondir((Altitude/ 8.3),1) -- hPa +SinusHauteurSoleil = math.sin(math.rad(HauteurSoleil)) +M0 = math.sqrt(1229 + math.pow(614 * SinusHauteurSoleil,2)) - 614 * SinusHauteurSoleil +M = M0 * PressionRelative/PressionAbsolue +if( DEBUG == 'OUI') then + print("Pression relative locale = " .. PressionRelative .. " hPa") + print("Pression absolue atmosphère = " .. PressionAbsolue .. " hPa") + print("Coefficient d'attenuation = " .. M ) +end +--------------------------------- +-- Récupérer message SYNOP sur le site Ogimet +heureUTCmoins1 = os.date("!%H")-1 +if string.len(heureUTCmoins1) == 1 then + heureUTCmoins1 = "0" .. heureUTCmoins1 +end +UTC = os.date("%Y%m%d").. heureUTCmoins1.."00" -- os.date("!%M") +local WMOID = jsonLocation.current_observation.display_location.wmo +print("WMOID="..WMOID) +local ogimet=assert(io.popen('curl "http://www.ogimet.com/cgi-bin/getsynop?block='..WMOID..'&begin='..UTC..'"')) +local synop = ogimet:read('*all') +ogimet:close() +rslt = split(synop,",") +CodeStation = rslt[1] +rslt = split(synop, " "..CodeStation.. " ") +Trame = string.gsub(rslt[2], "=", "") +Trame = CodeStation .." ".. Trame +rslt = split(Trame, " ") +if( DEBUG == 'OUI') then + print("Horodatage UTC = " .. UTC) + print("Station SYNOP = " .. WMOID) +end +--------------------------------- +-- Récupérer le premier caractere du 3eme mot = Nebulosité en Octa +Octa = string.sub(rslt[3], 1, 1) +--print(rslt[3]) +-- 0 Pas de couverture nuageuse +-- 1-8 Huitième +-- 9 Brouillard +-- / Couverture indiscernable +-- cas particulier si valeur indéterminé un slash est renvoyé. +if Octa == "/" then + -- si la couverture est indiscernable, on reprend l'ancienne valeur + -- cela evite les violentes cassures dans la courbe + --Octa = uservariables['octa'] + Octa = arg[1] +elseif Octa == "9" then + Octa = 8 +end +if( DEBUG == 'OUI') then + print( Octa .. " Octa") +end +-- stockage de la variable octa +--commandArray['Variable:octa']=tostring(Octa) +os.execute('/usr/bin/curl "http://127.0.0.1:8080/json.htm?type=command¶m=updateuservariable&idx='..idxOcta..'&vname=octa&vtype=0&vvalue='..tostring(Octa)..'"') + + +--------------------------------- +-- Facteur d'atténuation des couches nuageuses Kc +-- Kc=1-(0.75*((OCTA)**(3.4)) +Kc=1-0.75*(math.pow(Octa/8,3.4)) +if( DEBUG == 'OUI') then + print("Kc = " .. Kc) +end +--------------------------------- +-- Au lever/coucher du soleil, on atteind les limites de précisions de ces calculs. +-- J'interrompts donc le calcul de radiation dès 1°. +if HauteurSoleil > 1 then +-- Radiation directe + RadiationDirecte = RadiationAtm * math.pow(0.6,M) * SinusHauteurSoleil +-- Radiation Diffuse + RadiationDiffuse = RadiationAtm * (0.271 - 0.294 * math.pow(0.6,M)) * SinusHauteurSoleil +-- Radiation totale + RadiationTotale = RadiationDiffuse + RadiationDirecte +-- Radiation en Lux : -- 1 Lux = 0,0079 W/m² + Lux = RadiationTotale / 0.0079 + --Lux = ConstanteRadiationLux / ConstanteRatiationSolaire * RadiationTotale +-- Le rayonnement solaire avec ciel nuageux + RTOTC = RadiationTotale * Kc +-- Radiation en Lux pondéré + -- LuxPondere = ConstanteRadiationLux / ConstanteRatiationSolaire * RTOTC + LuxPondere = RTOTC / 0.0079 + print("Radiation totale en lux pondéré = ".. arrondir(LuxPondere,2).." Lux") + if( DEBUG == 'OUI') then + print("RadiationDirecte = ".. arrondir(RadiationDirecte,2) .." W/m²") + print("Radiation Diffuse = ".. arrondir(RadiationDiffuse,2) .." W/m²") + print("Radiation totale = " .. arrondir(RadiationTotale,2) .." W/m²") + print("Radiation totale en lux = ".. arrondir(Lux,2).." Lux") + print("Le rayonnement solaire avec pondération = " .. arrondir(RTOTC,2)) + end +else + --le soleil est trop bas + RTOTC = 0 + LuxPondere = 0 +end + --mise à jour du dispositif + os.execute('/usr/bin/curl "http://127.0.0.1:8080/json.htm?type=command¶m=udevice&idx='..idxLux..'&svalue="'..tostring(LuxPondere)..' -s -o /dev/null') diff --git a/lua/script_device_Cameras.lua b/lua/script_device_Cameras.lua new file mode 100755 index 0000000..af432c6 --- /dev/null +++ b/lua/script_device_Cameras.lua @@ -0,0 +1,74 @@ +require "scripts/lua/functions" + +commandArray = {} + +-- ------------------------------------------------------------------------------ +--recupere les minutes +-- ------------------------------------------------------------------------------ +time=os.time() +minutes=tonumber(os.date('%M',time)) +jour=tonumber(os.date('%w',time)) +heures=tonumber(os.date('%H',time)) +heurmin= heures * 60 + minutes + +-- ------------------------------------------------------------------------------ +-- Determination de l'augmentation de la temperature exterieure +-- ------------------------------------------------------------------------------ +if devicechanged['DETECTION_CAMERA1'] then + print("--------------Detection camera 1--------------------------------") + +-- if (otherdevices['Presence'] == 'Off' or otherdevices['Vacances'] == 'On' +-- or heures <= 11 or heures >= 21 +--) then + commandArray['SendNotification']='Alerte intrusion '..tostring(heures)..':'..tostring(minutes)..' #Attention Detection intrusion par camera 1#0' +-- end + +-- print("------------------------------------------------------------------") +end + +-- ------------------------------------------------------------------------------ +-- Detecteur de fumée, on allume les lumières et on ouvre les volets +-- ------------------------------------------------------------------------------ +if devicechanged['DétecteurFuméeCuisine'] then + debug("--------------Detecteur fumée --------------------------------") + + if (otherdevices['Presence'] == 'Off' or otherdevices['Vacances'] == 'On') then + commandArray['SendNotification']='Alerte détection de fumée '..tostring(heures)..':'..tostring(minutes)..' #Attention Detection fumée#0' + else + if uservariables['Dark'] == "True" then + commandArray['VoletsSalon'] = 'Off' + commandArray['LumieresSalon'] = 'On' + end + end + + debug("------------------------------------------------------------------") +end + +-- ------------------------------------------------------------------------------ +-- Réglage volume +-- ------------------------------------------------------------------------------ +if devicechanged['VolumeSonoJasper'] then + print("--------------Volume Sono Jasper --------------------------------") + + local slash = '\\' + + --local val = os.capture(cmd2) + -- print(tostring(val)) + local cmd = "/opt/domoticz/scripts/changevol.sh " + + os.execute('/opt/domoticz/scripts/changevol.sh &') + print("Réglage volume " .. cmd) + + print("------------------------------------------------------------------") +end + + + +--debug("temperature lue par otherdevice "..otherdevices_svalues['Bureau']) + +--debug(round(timeofday['SunsetInMinutes'] / 60, 0)..'H'..timeofday['SunsetInMinutes'] % 60) +--debug(round(timeofday['SunriseInMinutes'] / 60, 0)..'H'..timeofday['SunriseInMinutes'] % 60) + +--debug("################################# SUNSET "..uservariables['Couche']) + +return commandArray diff --git a/lua/script_device_Detection.lua b/lua/script_device_Detection.lua new file mode 100755 index 0000000..85f0fd1 --- /dev/null +++ b/lua/script_device_Detection.lua @@ -0,0 +1,162 @@ +require "scripts/lua/functions" + +commandArray = {} + +-- ------------------------------------------------------------------------------ +--recupere les minutes +-- ------------------------------------------------------------------------------ +time=os.time() +minutes=tonumber(os.date('%M',time)) +jour=tonumber(os.date('%w',time)) +day=tonumber(os.date('%d',time)) + +heures=tonumber(os.date('%H',time)) +heurmin= heures * 60 + minutes +mois=tonumber(os.date('%m',time)) + +extinction = uservariables['HEURE_EXTINCTION_FEUX'] + +-- ------------------------------------------------------------------------------ +-- Derniere détection +-- ------------------------------------------------------------------------------ +if devicechanged['Detecteur Salon'] or devicechanged['Detecteur Bureau'] then + commandArray['Variable:DerniereDetection'] = tostring(heures)..":"..tostring(minutes) + debug("DerniereDetection"..tostring(heures)..":"..tostring(minutes)) +end + +-- Quelqu'un est reveillé on ouvre les volets +if devicechanged['Detecteur Bureau'] or devicechanged['Detecteur Salon'] then + if ((heures >= 6) and (heures <= 9)) + and otherdevices['VoletPorteSalon'] == 'Closed' + and lastUpdateOfDevice('VoletPorteSalon') > 120 + then + os.execute("/opt/domoticz/scripts/volets3.sh Off &") + end + if (heures >= 23) + and otherdevices['VoletPorteSalon'] == 'Open' + then + -- os.execute("/opt/domoticz/scripts/volets2.sh On &") + end +end + +-- Volets + +-- ------------------------------------------------------------------------------ +-- Lampes allumees si presence détéctée +-- ------------------------------------------------------------------------------ +if devicechanged['Detecteur Bureau'] or devicechanged['Detecteur Salon'] + --or devicechanged['Lux'] + or devicechanged['Presence'] or + devicechanged['Philae'] or devicechanged['Akhesa'] or + devicechanged['Moi'] or devicechanged['Domi'] or + devicechanged['Theo'] or devicechanged['Manon'] or + devicechanged['DetectionCamera1'] + --or true +then + print("LAMPE : test allumage lampes") + local sunriseMin = heureEnMinute(uservariables["Lever"]) + local now = 60 * heures + minutes + + if (otherdevices['Vacances'] == 'On' or otherdevices['Presence'] == 'Off' + or ((mois >= 6 and mois <= 7) or (mois == 8 and day < 15))) then + print("LAMPE : desactivation"..tostring(mois)..' '..tostring(day)) + + switchLightsIfNeeded('Off') + elseif (otherdevices['Vacances'] == 'Off' and otherdevices['Presence'] == 'On') then + + if (whenDark() <= 15) then -- and otherdevices['VoletPorteSalon'] == 'Open') then + if ( + (heures >= 7 and heures <= 10 and not josdJourChome()) + or (heures >= 14 and + ( + (heures < 22) --or (heures == 22 and minutes < 30) + ) + ) + ) then + print("LAMPE Allumer les lampes") + switchLightsIfNeeded('On') + else + if (heures > 22) or heures < 7 then + switchLightsIfNeeded('Off') + print("LAMPE Eteindre les lampes") + end + end + else + if (now > sunriseMin) then -- and lum > luxMini) then + switchLightsIfNeeded('Off') + print("LAMPE Eteindre les lampes") + elseif (heures >= 22) or heures < 7 then + switchLightsIfNeeded('Off') + print("LAMPE Eteindre les lampes") + end + end + else + print("LAMPE Dans le else "..tostring(heures)) + end +end + +--end + +-- ------------------------------------------------------------------------------ +-- Envoi de notification si detection en absence +-- ------------------------------------------------------------------------------ +-- Vacances +if devicechanged['Detecteur Salon'] and (otherdevices['Vacances'] == 'On' or otherdevices['Presence'] == 'Off') then + debug("Detection en absence") + commandArray['SendNotification']='Mode absence#Une presence a ete detectee pres de la tele.#0' +end +-- Vacances +if devicechanged['Detecteur Bureau'] and (otherdevices['Vacances'] == 'On' or otherdevices['Presence'] == 'Off') then + debug("Detection en absence") + commandArray['SendNotification']='Mode absence#Une presence a ete detectee dans le bureau.#0' +end + + +-- ------------------------------------------------------------------------------ +-- Derniere détection +-- ------------------------------------------------------------------------------ +if devicechanged['Detecteur Salon'] or devicechanged['Detecteur Bureau'] then + commandArray['Variable:DerniereDetection'] = tostring(heures)..":"..tostring(minutes) + debug("DerniereDetection"..tostring(heures)..":"..tostring(minutes)) +end + +-- Quelqu'un est reveillé on ouvre les volets +if false and devicechanged['Detection_Tennis'] then + value = tonumber(otherdevices['Detection_Tennis']) + print("nombre de Detection_Tennis="..tostring(value).." jour="..jour) + + + heure_debut = 21 + heure_fin = 8 + if jour == 1 then + heure_debut = 8 + end + if jour == 2 then + heure_debut = 21 + end + -- Jour 3 = Mercredi + if jour == 3 then + heure_debut = 23 + end + if jour == 4 then + heure_debut = 20 + end + if jour == 5 then + heure_debut = 20 + end + if jour == 6 then + heure_debut = 19 + end + if jour == 7 then + heure_debut = 20 + end + + + if (((heures >= heure_debut) or (heures <= 8)) and value > 0) + then + commandArray['SendNotification']='Detection présence au tennis club après 23h#Une presence a ete detectee dans le bureau http://souti56.ddns.net:8081/.#0' + end + +end + +return commandArray diff --git a/lua/script_device_Energie.SAVE b/lua/script_device_Energie.SAVE new file mode 100755 index 0000000..146f759 --- /dev/null +++ b/lua/script_device_Energie.SAVE @@ -0,0 +1,628 @@ +-- demo device script +-- script names have three name components: script_trigger_name.lua +-- trigger can be 'time' or 'device', name can be any string +-- domoticz will execute all time and device triggers when the relevant trigger occurs +-- +-- copy this script and change the "name" part, all scripts named "demo" are ignored. +-- +-- Make sure the encoding is UTF8 of the file +-- +-- ingests tables: devicechanged, otherdevices,otherdevices_svalues +-- +-- device changed contains state and svalues for the device that changed. +-- devicechanged['yourdevicename']=state +-- devicechanged['svalues']=svalues string +-- +-- otherdevices and otherdevices_svalues are arrays for all devices: +-- otherdevices['yourotherdevicename']="On" +-- otherdevices_svalues['yourotherthermometer'] = string of svalues +-- +-- Based on your logic, fill the commandArray with device commands. Device name is case sensitive. +-- +-- Always, and I repeat ALWAYS start by checking for the state of the changed device. +-- If you would only specify commandArray['AnotherDevice']='On', every device trigger will switch AnotherDevice on, which will trigger a device event, which will switch AnotherDevice on, etc. +-- +-- The debug command will output lua debug statements to the domoticz log for debugging. +-- List all otherdevices states for debugging: +-- for i, v in pairs(otherdevices) do debug(i, v) end +-- List all otherdevices svalues for debugging: +-- for i, v in pairs(otherdevices_svalues) do debug(i, v) end +-- +-- TBD: nice time example, for instance get temp from svalue string, if time is past 22.00 and before 00:00 and temp is bloody hot turn on fan. +require "scripts/lua/functions" + +time = os.time() +annee = os.date('%Y',time) +mois = os.date('%m',time) +heures = tonumber(os.date('%H',time)) +minutes = tonumber(os.date('%M',time)) +secondes = tonumber(os.date('%S',time)) + +jour = tonumber(os.date('%w',time)) +jour_s = os.date('%d',time) +jour_y = tonumber(os.date('%j',time)) + +heurmin = heures * 60 + minutes + +PUISSANCE_DELESTAGE = 750 -- Watts + +disable_radiateur = false + +function callExternal(command) + local handle = io.popen(command) + local result = handle:read("*a") + handle:close() + --debug("Commande = "..command.." "..result) + return result +end + +function update_meter(device, id, power, energy, index) + commandArray[index] = {['UpdateDevice'] = id .. "|0|" .. power .. ";" .. energy} +end + +local function round(num, dec) + --debug("Round "..tostring(num)) + + return ( math.floor( tonumber(num) * 10^dec ) / 10^dec ) +end + +local function updatenum(dev, value1) + print("NRJ updatenum "..dev..tostring(value1)) + --local cmd = string.format("%d|0|%d", otherdevices_idx[dev], math.floor(value1)) + local cmd = tostring(otherdevices_idx[dev]).."|0|"..tostring(round(value1, 3)) + + table.insert (commandArray, { ['UpdateDevice'] = cmd } ) +end + +function getConsommationHC(idx) + date=annee..'-'..mois..'-'..jour_s + --date_end=annee..'-'..mois..'-'..math.floor(jour_s + 1) + + -- query = 'select max(value) - min(value) from Meter mc where DeviceRowID =' ..idx + -- .. ' and date like "' .. date ..'%"' + -- .. ' and (date >= "' .. date_deb.. ' 21:29:59" or date <= "'.. date_deb ..' 05:30:00")' + + + query = 'select sum(hc) from (select max(value) - min(value) as hc from Meter mc where DeviceRowID =' ..idx + .. ' and date like "' .. date ..'%"' + .. ' and (date >= "' .. date.. ' 21:29:59"' + .. ' and date < "' .. date ..' 23:59:59")' + .. ' union all' + .. ' select max(value) - min(value) as hc from Meter mc where DeviceRowID =' .. idx + .. ' and date like "' .. date ..'%"' + .. ' and (date < "' .. date ..' 05:30:00")' + .. ' and (date > "' .. date ..' 00:00:00")' + .. ') as c' + + --query = 'select max(value) - min(value) from Meter mc where DeviceRowID =' ..idx + -- .. ' and date like "' .. date ..'%"' + -- .. ' and not(date > "' .. date.. ' 05:29:59" and date <= "'.. date ..' 21:30:00")' + + + debug("query="..query) + local bSuccess, aRows, iCount = executeQuery(idx, query) + + if aRows[1][1] then + debug("Retour executeQuery "..tostring(bSuccess)..' '..aRows[1][1]) + return aRows[1][1] + end + debug('retour à 0') + return 0 +end +function getConsommationHP(idx) + date=annee..'-'..mois..'-'..jour_s + query = 'select max(value) - min(value) from Meter mc where DeviceRowID =' ..idx + .. ' and date like "' .. date ..'%"' + .. ' and (date > "' .. date.. ' 05:29:59" and date <= "'.. date ..' 21:30:00")' + + --debug("query="..query) + local bSuccess, aRows, iCount = executeQuery(idx, query) + + --debug("Retour executeQuery "..tostring(bSuccess)..' '..aRows[1][1]) + return aRows[1][1] +end + +function deleteWrongData(idx) + + -- delete from MultiMeter where DeviceRowid = 1135 and date >= "2021-06-02 00:00:00" + -- and date like "2021-06-02 00:00%"; + date=annee..'-'..mois..'-'..jour_s + query = 'delete from MultiMeter where DeviceRowID =' ..idx + .. ' and date like "' .. date ..' 00:00%"' + .. ' and (date >= "' .. date.. ' 00:00:00")' + + debug("query delete="..query) + local bSuccess, aRows, iCount = executeQuery(idx, query) + +end + + +commandArray = {} + + if devicechanged['RadiateurGrenier'] then + print("Dimmer Radiateur "..otherdevices_svalues['RadiateurGrenier']..tostring(otherdevices['RadiateurGrenier'])) + local consigne = tonumber(otherdevices_svalues['RadiateurGrenier']) + + print("Dimmer Radiateur grenier="..tostring(consigne)) + if consigne <= 0 or otherdevices['RadiateurGrenier'] == "Off" then + -- command = 'curl -m 3 "http://192.168.177.240/stop"' + command = 'curl -m 3 "http://192.168.197.193/stop"' + else + -- command = 'curl -m 3 "http://192.168.177.240/exact?value=' .. tostring(consigne * 7).. '"' + command = 'curl -m 3 "http://192.168.197.193/exact?value=' .. tostring(consigne * 3.5).. '"' + end + callExternal(command) + end + +-- ================================================================== +-- INTENSITE_GENERALE +-- ================================================================== +--if (devicechanged['CONSOMMATION_GENERALE']) then +function calcul() + --local tab = getValuesInTab('Oregon_Conso') + --debug("Conso "..otherdevices['Oregon_Conso']) + --values = split(otherdevices['Oregon_Conso'], ";") + --if (tonumber(values[1]) < 0) then + -- if (tonumber(values[1]) == -0.1) then + -- watt = - tonumber(values[2]) + -- else + -- watt = tonumber(values[1]) * 100 - tonumber(values[2]) + -- end + --else + -- watt = (tonumber(values[1]) * 100 + tonumber(values[2])) --/ 1.42 + --end + values2 = split(otherdevices['CONSOMMATION_GENERALE'], ";") + print("NRJ Solaire CONSOMMATION_GENERALE tabs "..otherdevices['CONSOMMATION_GENERALE']) + + watt = tonumber(values2[1]) + for deviceName,deviceValue in pairs(devicechanged) do + if deviceName=="CONSOMMATION_GENERALE_Utility" then + watt = deviceValue + end + + debug ("Device based event fired on '"..deviceName.."', value '"..tostring(deviceValue).."'"); + end + + debug("Conso "..tostring(watt)) + + --debug("mesure"..otherdevices['INTENSITE_GENERALE']) + amp = watt / 230 --math.max(0,round(otherdevices['INTENSITE_GENERALE'],3) - 0.54) * 7 / 8 + + watt_conso = watt --* 0.9459 + updatenum('INTENSITE_GENERALE', amp) + + debug("consommation Amp="..tostring(amp).." conso="..tostring(watt_conso)) + --updatenum('CONSOMMATION_GENERALE', round(watt_conso,0)) + + local tab = getValuesInTab('SolaireProduction') + local watt_solaire = tonumber(tab[1]) + local watt_solaire_jour = otherdevices_svalues['SolaireProduction'] + if watt_solaire == nil then + watt_solaire = 0 + end + + debug("Suivi "..tostring(watt_conso - watt_solaire)) + if (minutes%5 == 0 and secondes < 8) then + date = annee..'-'..mois..'-'..jour_s + + counter_conso = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select counter from Meter_Calendar where DeviceRowID='.. + otherdevices_idx['Consommation_Apparente']..' order by Date desc limit 1;"') + counter_conso=tonumber(counter_conso) or 0 + debug('counter_conso='..counter_conso) + + value_conso = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select Value from Meter where DeviceRowID=='.. + otherdevices_idx['Consommation_Apparente']..' order by Date desc limit 1;"') + value_conso=tonumber(value_conso) or 0 + debug('value_conso='..value_conso) + + + counter_solar = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select counter from Meter_Calendar where DeviceRowID='.. + otherdevices_idx['SolaireProduction']..' order by Date desc limit 1;"') + counter_solar=tonumber(counter_solar) or 0 + debug('counter_solar='..counter_solar) + + value_solar = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select Value from Meter where DeviceRowID=='.. + otherdevices_idx['SolaireProduction']..' order by Date desc limit 1;"') + value_solar=tonumber(value_solar) or 0 + debug('value_solar='..value_solar) + + counter_injection = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select counter from Meter_Calendar where DeviceRowID='.. + otherdevices_idx['INJECTION']..' order by Date desc limit 1;"') + counter_injection=tonumber(counter_injection) or 0 + debug('counter_injection='..counter_injection) + + value_injection = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select Value from Meter where DeviceRowID=='.. + otherdevices_idx['INJECTION']..' order by Date desc limit 1;"') + value_injection=tonumber(value_injection) or 0 + debug('value_injection='..value_injection) + + + counter_radiateur = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select counter from Meter_Calendar where DeviceRowID='.. + otherdevices_idx['Injection_Radiateur']..' order by Date desc limit 1;"') + counter_radiateur=tonumber(counter_radiateur) or 0 + debug('counter_radiateur='..counter_radiateur) + + value_radiateur = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select Value from Meter where DeviceRowID=='.. + otherdevices_idx['Injection_Radiateur']..' order by Date desc limit 1;"') + value_radiateur=tonumber(value_radiateur) or 0 + debug('value_radiateur='..value_radiateur) + + + cumul_solar = value_solar - counter_solar + cumul_injection = value_injection - counter_injection + consommation = value_conso - counter_conso + cumul_radiateur = value_radiateur - counter_radiateur + + debug('conso='..consommation) + debug('cumul_solar='..cumul_solar) + debug('cumul_injection='..cumul_injection) + debug('cumul_radiateur='..cumul_radiateur) + + if (cumul_solar > 0) then + debug("auto consommation="..tostring( + round((100 * (cumul_solar - cumul_injection) / cumul_solar),1)) + ) + commandArray['AUTO_CONSOMMATION'] = otherdevices_idx['AUTO_CONSOMMATION'] ..'|0|' .. tostring( + round((100 * (cumul_solar - cumul_injection) / cumul_solar),1) + ) + updatenum('AUTO_CONSOMMATION', round((100 * (cumul_solar - cumul_injection) / cumul_solar),1) ) + + end + + if (consommation > 0) then + debug("auto production="..tostring(100 * cumul_solar / (cumul_solar + consommation))) + updatenum('AUTO_PRODUCTION', round(100 * cumul_solar / (cumul_solar + consommation),1)) + + end + updatenum('COUVERTURE', round(100 * value_solar / (value_conso + value_solar),1)) + + + if (cumul_solar > 0) then + updatenum('Consommation_Efficace', round(100 *((cumul_solar - cumul_radiateur - cumul_injection) / cumul_solar), 1)) + else + updatenum('Consommation_Efficace', 0) + end + end + +end + +if (devicechanged['Mesure_Courant']) then + print('NRJ Mesure_Courant '..otherdevices['Mesure_Courant']) + values2 = split(otherdevices['Mesure_Courant'], ";") + debug("Solaire Mesure courant tabs ") --..otherdevices['Mesure_Courant']) + + + watt = tonumber(values2[1]) + if (watt > 1600) then + watt = 0; + end + for deviceName,deviceValue in pairs(devicechanged) do + if deviceName=="Mesure_Courant_Utility" then + watt = deviceValue + end + + debug ("Device based event fired on '"..deviceName.."', value '"..tostring(deviceValue).."'"); + end + print("NRJ Solaire Mesure courant "..tostring(watt)) + + --updatenum('SolaireIntensite', round(watt / 230,3)) + --updatenum('INTENSITE_GENERALE', round(watt / 230,3)) + watt = math.abs(watt) --- 56 + --if (watt < 0 or (heures <= 7 or heures >= 21)) then + -- watt = 0 + --end + + --debug("Intensite solaire "..devicechanged['SolaireIntensite']) + amp = math.abs(watt / 230); --math.max(0, round(otherdevices['SolaireIntensite'],3) - 0.54) *1.18 + updatenum('SolaireIntensite', amp) + + print("NRJ # 2 # production amp="..tostring(amp).." watt="..tostring(watt)) + --debug("NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN") + if (watt == nil or watt == "NAN") then + watt = 0 + end + + updatenum('SolaireProduction', round(watt,1)) + + watt_solaire = math.abs(watt) + local tab = getValuesInTab('CONSOMMATION_GENERALE') + local watt_conso = tonumber(tab[1]) + local tab_r = getValuesInTab('Consommation_Apparente') + local watt_reel = tonumber(tab_r[1]) + if (watt_reel > 0) then + updatenum('CONSOMMATION_GENERALE', watt_reel) + if watt_solaire > 0 then + updatenum('COUVERTURE_INSTANTANEE', round(100 * (watt_solaire / (watt_solaire + watt_reel)), 1)) + else + updatenum('COUVERTURE_INSTANTANEE', 0) + end + + else + updatenum('COUVERTURE_INSTANTANEE', 100) + updatenum('CONSOMMATION_GENERALE', 0) + end + calcul() +end + +if (devicechanged['Consommation_Apparente']) then + print("NRJ Consommation_Apparente ================================================") + + values2 = split(otherdevices['Consommation_Apparente'], ";") + watt = tonumber(values2[1]) + + for deviceName,deviceValue in pairs(devicechanged) do + if deviceName=="Consommation_Apparente_Utility" then + -- watt = deviceValue + watt = round(deviceValue, 2) + debug ("Device based event fired on '"..deviceName.."', value "..tostring(round(deviceValue, 2))); + + end + + -- debug ("Device based event fired on '"..deviceName.."', value "..tostring(tonumber(deviceValue))); + end + + debug("Solaire Consommation_Apparente "..tostring(watt)) + + values = split(otherdevices['SolaireProduction'], ";") + --debug("Solaire production "..otherdevices['SolaireProduction']) + + watt_solaire = values[1] + + values2 = split(otherdevices['Mesure_Courant'], ";") + --debug("Solaire production mesure courant "..otherdevices['Mesure_Courant']) + + watt_solaire = values[1] --+ values2[1] + if watt_solaire == "NAN" then + watt_solaire = "0" + end + + injection = split(otherdevices['INJECTION'], ";") + debug(injection[1]) + + local debut_injection = -14 + local fin_injection = 14 + + local currentTemp = getTemperatureFromDevice('Bureau') + + debug("Solaire production temperature Exterieur_Cellier "..tostring(currentTemp).." "..tostring(watt_solaire)) + + if disable_radiateur == false then + command = 'curl -s -m 3 "http://192.168.125.11"|grep "

"|awk -F">" \'{print $2}\'|awk -F"<" \'{print $1}\'' + --local handle = io.popen(command) + --local result = handle:read("*a") + --handle:close() + result = callExternal(command) + print("quick_value result niveau d'injection= "..result) + + if --tonumber(watt_solaire) < 50 or + uservariables["Dark"] == "True" or (currentTemp >= 24 and (jour_y > 150 and jour_y < 260)) then + -- commandArray['Dimmer'] = 'Set Level: 30' + else + if result == 0 or result == "" or result == nil or result == "NAN" then + result = 0 + end + --if (tonumber(watt_solaire) < result * (PUISSANCE_DELESTAGE / 100) and tonumber(watt) > 0 ) or tonumber(watt) > fin_injection then + -- debug("Solaire quick_value stop") + -- command = 'curl -m 3 "http://192.168.125.11/stop"' + -- callExternal(command) + --else + if (watt < debut_injection) then + local to_inject = math.abs(watt) -- + tonumber(result) * (PUISSANCE_DELESTAGE / 100) + local quick_value = math.floor(to_inject / (PUISSANCE_DELESTAGE / 100)) + + --print("Solaire PLUS quick_value="..tostring(quick_value).." to_inject="..tostring(to_inject)) + --local quick_value = math.floor(math.abs(watt / (PUISSANCE_DELESTAGE / 100)) - tonumber(result)) --/ 2 + print("Solaire quick_value plus="..tostring(quick_value).." watt="..tostring(watt)) + if (quick_value > 0) then + command = 'curl -m 3 "http://192.168.125.11/plus?value=' .. tostring(quick_value).. '"' + callExternal(command) + end + else + if (watt > fin_injection) then + local to_inject = watt --tonumber(result) * (PUISSANCE_DELESTAGE / 100) - watt + local quick_value = math.abs(math.floor(to_inject / (PUISSANCE_DELESTAGE / 100))) + --local quick_value = math.floor(tonumber(result) - math.abs((watt) / (PUISSANCE_DELESTAGE / 100)) ) + + --print("Solaire MINUS quick_value="..tostring(quick_value).." to_inject="..tostring(to_inject)) + print("Solaire quick_value minus="..tostring(quick_value).." watt="..tostring(watt)) + command = 'curl -m 3 "http://192.168.125.11/minus?value=' .. tostring(quick_value).. '"' + callExternal(command) + end + end + --end + end + + + end + + if result == 0 or result == "" or result == nil or result == "NAN" then + print("result nil value") + updatenum('TOTAL_AUTOCONSOMMATION', 0) + else + if (tonumber(result) == 1) then + commandArray['Dimmer'] = 'Set Level: 30' + result=0 + end + local injection_radiateur = tonumber(result) * PUISSANCE_DELESTAGE / 100 + updatenum('Injection_Radiateur', injection_radiateur) + updatenum('TOTAL_AUTOCONSOMMATION', round(watt_solaire - injection[1] - math.abs(injection_radiateur), 0)) + end + + -- ======================================================================== + + + if false then + if tonumber(watt_solaire) < 50 or uservariables["Dark"] == "True" then + commandArray['Dimmer'] = 'Set Level: 30' + else + if (watt < debut_injection and tonumber(watt_solaire) > 150) then + debug("Allumage radiateur pour éviter l'injection " .. tostring(lastUpdateOfDevice('RadiateurBureau'))) + + if watt < debut_injection then + local quick_value = math.floor(math.abs(watt / (PUISSANCE_DELESTAGE / 100))) + debug("quick_value plus="..tostring(quick_value)) + command = 'curl -m 3 "http://192.168.125.11/plus?value=' .. tostring(quick_value).. '"' + callExternal(command) + --os.execute('curl -m 3 "http://192.168.125.11/plus?value=' .. tostring(quick_value).. '"'); + else + commandArray['Dimmer'] = 'Set Level: 40' + end + else + debug("Pas de consommation necessaire") + if (watt > 150) then + commandArray['Dimmer'] = 'Set Level: 30' + else + if (watt > fin_injection) then + local quick_value=math.floor(math.abs(watt / (PUISSANCE_DELESTAGE / 100))) + debug("quick_value minus="..tostring(quick_value)) + + command = 'curl -m 3 "http://192.168.125.11/minus?value=' .. tostring(quick_value).. '"' + callExternal(command) + --os.execute('curl -m 3 "http://192.168.125.11/minus?value=' .. tostring(quick_value).. '"'); + else + commandArray['Dimmer'] = 'Set Level: 50' + end + end + end + end + command = 'curl -s -m 3 "http://192.168.125.11"|grep "

"|awk -F">" \'{print $2}\'|awk -F"<" \'{print $1}\'' + --local handle = io.popen(command) + --local result = handle:read("*a") + --handle:close() + result = callExternal(command) + debug("result niveau d'injection= "..result) + + if result == nil then + else + if (tonumber(result) == 1) then + commandArray['Dimmer'] = 'Set Level: 30' + result=0 + end + local injection_radiateur = tonumber(result) * PUISSANCE_DELESTAGE / 100 + updatenum('Injection_Radiateur', injection_radiateur) + updatenum('TOTAL_AUTOCONSOMMATION', round(watt_solaire - math.abs(injection_radiateur), 0)) + end + else + end + + -- ======================================================================== + + if (watt < 0) then + debug("Watt injection "..watt) + + updatenum('INJECTION', - round(watt,0)) + updatenum('TOTAL_INJECTION', - round(watt,0)) + else + updatenum('INJECTION', 0) + updatenum('TOTAL_INJECTION', 0) + end + + -- ========================================================= + + --Calculate what the house is consuming + -- Get current date & time + t1 = os.time() + local currentDate = os.date("*t"); -- sets up currentDate.[table] + -- (currentDate.year [full], .month [1-12], .day [1-31], .hour [0-23], .min [0-59], .sec [0-59], .wday [0-6 {Sun-Sat}]) + sCurrentTime = currentDate.year .. "-" .. currentDate.month .. "-" .. currentDate.day .. " " .. currentDate.hour .. ":" .. currentDate.min .. ":" .. currentDate.sec + + counter_solar = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select counter from Meter_Calendar where DeviceRowID='.. + otherdevices_idx['SolaireProduction']..' order by Date desc limit 1;"') + counter_solar=tonumber(counter_solar) or 0 + debug('counter_solar='..counter_solar) + + value_solar = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select Value from Meter where DeviceRowID=='.. + otherdevices_idx['SolaireProduction']..' order by Date desc limit 1;"') + value_solar=tonumber(value_solar) or 0 + debug('value_solar='..value_solar) + + + --------------------------------------------------------------------------------------- + -- Solaire 2 + date = annee..'-'..mois..'-'..jour_s + + counter_solar2 = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select counter from Meter_Calendar where DeviceRowID='.. + otherdevices_idx['Mesure_Courant'].. + ' and date like "' .. date ..'%"'.. + ' order by Date desc limit 1;"') + counter_solar2=tonumber(counter_solar2) or 0 + debug('counter_solar2='..counter_solar2) + + value_solar2 = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select Value from Meter where DeviceRowID=='.. + otherdevices_idx['Mesure_Courant'].. + ' and date like "' .. date ..'%"'.. + ' order by Date desc limit 1;"') + value_solar2=tonumber(value_solar2) or 0 + debug('value_solar2='..value_solar2) + + -------------------------------------------------------------------------------------- + watt_p1 = getConsommationHP(1123) or 0 + watt_p2 = getConsommationHC(1123) or 0 + local cmd = '1135|0|' + --USAGE1= energy usage meter tariff 1, This is an incrementing counter + --USAGE2= energy usage meter tariff 2, This is an incrementing counter + --RETURN1= energy return meter tariff 1, This is an incrementing counter + --RETURN2= energy return meter tariff 2, This is an incrementing counter + --CONS= actual usage power (Watt) + --PROD= actual return power (Watt) + .. tostring(math.floor(watt_p1)) .. ';' + .. tostring(math.floor(watt_p2)) .. ';' + -- + value_solar2 - counter_solar2 + .. tostring(math.floor(value_solar - counter_solar + value_solar2 - counter_solar2)) .. ';' + .. '0;' + .. tostring(math.floor(math.max(0,watt) + watt_solaire)).. ';' + .. tostring(math.floor(watt_solaire)) --math.floor(ConsumoEnergyBalance / 1000)) --round(watt,0)) + + debug('Consommation_Reelle_2 '..cmd) + if heures == 23 and minutes == 59 and secondes >= 45 then + -- ignored + else + table.insert (commandArray, { ['UpdateDevice'] = cmd } ) + end + if heures == 00 and minutes == 05 and secondes <= 10 then + deleteWrongData(1135) + end + debug('when light=' .. tostring(whenLight())) + + -- ========================================================= + + local cmd = '1136|0|' + --USAGE1= energy usage meter tariff 1, This is an incrementing counter + --USAGE2= energy usage meter tariff 2, This is an incrementing counter + --RETURN1= energy return meter tariff 1, This is an incrementing counter + --RETURN2= energy return meter tariff 2, This is an incrementing counter + --CONS= actual usage power (Watt) + --PROD= actual return power (Watt) + .. '0;' + .. '0;' + .. '0;' + .. '0;' + .. tostring(math.floor(math.max(0,watt))).. ';' + .. '0' --math.floor(ConsumoEnergyBalance / 1000)) --round(watt,0)) + table.insert (commandArray, { ['UpdateDevice'] = cmd } ) + updatenum('Non_Couvert_2', math.floor(math.max(0,watt))) + + -- ========================================================= + +end + + + + +capacite=76 * 12 --Wh +charge=200 --Wh +decharge=50 --Wh +tension_charge_max_off=13.3 +tension_charge_max_on=13.8 +tension_injection_min=11.2 +tension_force_charge=10.8 + +--Initialise la commande de retour finale +commandArray={} + + + + + +return commandArray + diff --git a/lua/script_device_Energie.lua b/lua/script_device_Energie.lua new file mode 100755 index 0000000..91e6968 --- /dev/null +++ b/lua/script_device_Energie.lua @@ -0,0 +1,680 @@ +-- demo device script +-- script names have three name components: script_trigger_name.lua +-- trigger can be 'time' or 'device', name can be any string +-- domoticz will execute all time and device triggers when the relevant trigger occurs +-- +-- copy this script and change the "name" part, all scripts named "demo" are ignored. +-- +-- Make sure the encoding is UTF8 of the file +-- +-- ingests tables: devicechanged, otherdevices,otherdevices_svalues +-- +-- device changed contains state and svalues for the device that changed. +-- devicechanged['yourdevicename']=state +-- devicechanged['svalues']=svalues string +-- +-- otherdevices and otherdevices_svalues are arrays for all devices: +-- otherdevices['yourotherdevicename']="On" +-- otherdevices_svalues['yourotherthermometer'] = string of svalues +-- +-- Based on your logic, fill the commandArray with device commands. Device name is case sensitive. +-- +-- Always, and I repeat ALWAYS start by checking for the state of the changed device. +-- If you would only specify commandArray['AnotherDevice']='On', every device trigger will switch AnotherDevice on, which will trigger a device event, which will switch AnotherDevice on, etc. +-- +-- The debug command will output lua debug statements to the domoticz log for debugging. +-- List all otherdevices states for debugging: +-- for i, v in pairs(otherdevices) do debug(i, v) end +-- List all otherdevices svalues for debugging: +-- for i, v in pairs(otherdevices_svalues) do debug(i, v) end +-- +-- TBD: nice time example, for instance get temp from svalue string, if time is past 22.00 and before 00:00 and temp is bloody hot turn on fan. +require "scripts/lua/functions" + +time = os.time() +annee = os.date('%Y',time) +mois = os.date('%m',time) +heures = tonumber(os.date('%H',time)) +minutes = tonumber(os.date('%M',time)) +secondes = tonumber(os.date('%S',time)) + +jour = tonumber(os.date('%w',time)) +jour_s = os.date('%d',time) +jour_y = tonumber(os.date('%j',time)) + +heurmin = heures * 60 + minutes + +PUISSANCE_DELESTAGE = 750 -- Watts + +disable_radiateur = true + +function callExternal(command) + local handle = io.popen(command) + local result = handle:read("*a") + handle:close() + --debug("Commande = "..command.." "..result) + return result +end + +function update_meter(device, id, power, energy, index) + commandArray[index] = {['UpdateDevice'] = id .. "|0|" .. power .. ";" .. energy} +end + +local function round(num, dec) + --debug("Round "..tostring(num)) + + if (num and dec) then + return ( math.floor( tonumber(num) * 10^dec ) / 10^dec ) + end + return 0 +end + + +function getConsommationHC(idx) + date=annee..'-'..mois..'-'..jour_s + --date_end=annee..'-'..mois..'-'..math.floor(jour_s + 1) + + -- query = 'select max(value) - min(value) from Meter mc where DeviceRowID =' ..idx + -- .. ' and date like "' .. date ..'%"' + -- .. ' and (date >= "' .. date_deb.. ' 21:29:59" or date <= "'.. date_deb ..' 05:30:00")' + + + query = 'select sum(hc) from (select max(value) - min(value) as hc from Meter mc where DeviceRowID =' ..idx + .. ' and date like "' .. date ..'%"' + .. ' and (date >= "' .. date.. ' 21:29:59"' + .. ' and date < "' .. date ..' 23:59:59")' + .. ' union all' + .. ' select max(value) - min(value) as hc from Meter mc where DeviceRowID =' .. idx + .. ' and date like "' .. date ..'%"' + .. ' and (date < "' .. date ..' 05:30:00")' + .. ' and (date > "' .. date ..' 00:00:00")' + .. ') as c' + + --query = 'select max(value) - min(value) from Meter mc where DeviceRowID =' ..idx + -- .. ' and date like "' .. date ..'%"' + -- .. ' and not(date > "' .. date.. ' 05:29:59" and date <= "'.. date ..' 21:30:00")' + + + debug("query="..query) + local bSuccess, aRows, iCount = executeQuery(idx, query) + + if aRows[1][1] then + debug("Retour executeQuery "..tostring(bSuccess)..' '..aRows[1][1]) + return aRows[1][1] + end + debug('retour à 0') + return 0 +end +function getConsommationHP(idx) + date=annee..'-'..mois..'-'..jour_s + query = 'select max(value) - min(value) from Meter mc where DeviceRowID =' ..idx + .. ' and date like "' .. date ..'%"' + .. ' and (date > "' .. date.. ' 05:29:59" and date <= "'.. date ..' 21:30:00")' + + --debug("query="..query) + local bSuccess, aRows, iCount = executeQuery(idx, query) + + --debug("Retour executeQuery "..tostring(bSuccess)..' '..aRows[1][1]) + return aRows[1][1] +end + +function deleteWrongData(idx) + + -- delete from MultiMeter where DeviceRowid = 1135 and date >= "2021-06-02 00:00:00" + -- and date like "2021-06-02 00:00%"; + date=annee..'-'..mois..'-'..jour_s + query = 'delete from MultiMeter where DeviceRowID =' ..idx + .. ' and date like "' .. date ..' 00:00%"' + .. ' and (date >= "' .. date.. ' 00:00:00")' + + debug("query delete="..query) + local bSuccess, aRows, iCount = executeQuery(idx, query) + +end + + +-- ---------------------------------- +-- Gestion des batteries automatique +-- --------------------------------- + +function gestionBatterie(ip_controller) + + local attente_radiateur = false + local capacite=100 * 24 --Wh + local charge=390 --W + local decharge=270 --210 --W + local tension_charge_max_off=29.6 + local tension_charge_max_on=29.6 + local tension_injection_min_off=25.2 + local tension_injection_min_on=24.8 + local tension_force_charge=24.6 + local fact = 2 --2.43 + local regul = false + + -- Tension repos V Conso charge W + -- 11.35 330 + -- 12.35 270 + -- 12.8 233 + -- 12.67 190 + -- 13.33 66 + + url = "http://"..ip_controller.."/getData" + + --result = os.execute(curl..'"'..url..'"') + local jsonContent = getJSONContent(url) + --print(cmd) + + local statuses = decodeJSON(jsonContent) + --printTableAsTree(statuses) + + --updatenum("BatterieCharge", 0) + --updatenum("BatterieInjection", 0) + --local charge_theorique = (13.796 - tension) / 0.01213 -- -127.57 * tension + 1796.82 + if isempty(statuses) then -- or tension <= 0 then + print("BAT ERROR getData") + --switchOff('Batterie') + return 0 --commandArray + end + local tension = round(tonumber(statuses['V']) / 1000,2) -- tonumber(otherdevices['BatterieTension']) + if tension <= 10 then + print("BAT ERROR tension fausse") + --switchOff('Batterie') + return 0 --commandArray + end + + if (otherdevices['ForceChargeBatterie'] == 'On' and + ((tonumber(lastUpdateOfDevice('ForceChargeBatterie')) > 3 * 3600) or tension > tension_charge_max_on)) + then + commandArray['ForceChargeBatterie'] = "Off" + switchOff("ForceChargeBatterie") + end + if (statuses['CS'] == '3' and tonumber(statuses['PPV']) > 450 or (statuses['CS'] == '4' or statuses['CS'] == '5')) then + print("Radiateur solaire Actif CS="..statuses['CS'].." PPV="..statuses['PPV']) + disable_radiateur = false + else + print("Radiateur solaire Inactif CS="..statuses['CS'].." PPV="..statuses['PPV']) + disable_radiateur = true + command = 'curl -m 3 "http://192.168.125.11/stop"' + callExternal(command) + updatenum("Injection_Radiateur", 0) + end + + local decharge_theorique = 63.29 * tension - 697.5 + --decharge=150 --decharge_theorique + --charge=220 --charge_theorique + --print("BAT Power theorique "..tostring(charge_theorique)) + local temperature = round(tonumber(statuses['XY_T']) / 10,1) -- tonumber(otherdevices['BatterieTension']) + + updatenum("BatterieTension", tension) + updatenum("BatterieCharge", tonumber(statuses['PPV'])) + local decharge_tmp = tonumber(statuses['V']) * tonumber(statuses['IL']) / 1000000 + if decharge_tmp > 0 then + decharge = decharge_tmp + end + + updatenum("BatterieInjection", tonumber(statuses['V']) * tonumber(statuses['IL']) / 1000000) + updatenum("TemperatureBatterie", temperature) + --commandArray['UpdateDevice'] = "1195|0|"..tostring(tension) + --commandArray['UpdateDevice'] = "1196|0|"..tostring(temperature) + --commandArray['Batterie'] = ternary(statuses['PIN_POWER'] == 0, 'On', 'Off') + --commandArray['InjectionBatterie'] = ternary(statuses['PIN_INJECTION'] == 0, 'On', 'Off') + --commandArray['ChargeBatterie'] = ternary(statuses['PIN_CHARGE'] == 0, 'On', 'Off') + + local production = tonumber(split(otherdevices['SolaireProduction'], ";")[1]) + local injection = tonumber(split(otherdevices['Injection_Radiateur'], ";")[1]) + local injection_reseau = tonumber(split(otherdevices['INJECTION'], ";")[1]) + local chauffe = tonumber(split(otherdevices['Chauffe_Eau'], ";")[1]) + local conso = tonumber(split(otherdevices['Consommation_Apparente'], ";")[1]) + local nuages = tonumber(otherdevices['CouvertureNuageusePrevisionnelle']) + updatenum("Surplus", injection + injection_reseau) + + print("BAT injection="..tostring(injection) + ..' solaire='..tostring(production) + ..' chauffe='..tostring(chauffe) + ..' charge='..statuses['PPV'] + ..' decharge='..tostring(tonumber(statuses['V']) * tonumber(statuses['IL']) / 1000000) + ..' conso='..tostring(conso) + ..' tension='..tostring(tension) + ..' temperature='..tostring(temperature) + ) + if isempty(statuses) then -- or tension <= 0 then + print("BAT ERROR getData") + --switchOff('Batterie') + return 0 --commandArray + end + print("BAT PIN_CHARGE="..statuses['PIN_CHARGE'].." PIN_INJECTION="..statuses['PIN_INJECTION']) + -- status 1 = ON / 0 = OFF + + + if (uservariables['Dark'] == "True" and tonumber(statuses['PPV']) > 100) then + --switchOff('LUMIERE_PLANTE') + end + + return tonumber(statuses['PPV']) +end -- GestionBatterie + + +commandArray = {} + + if devicechanged['RadiateurGrenier'] then + print("Dimmer Radiateur "..otherdevices_svalues['RadiateurGrenier']..tostring(otherdevices['RadiateurGrenier'])) + local consigne = tonumber(otherdevices_svalues['RadiateurGrenier']) + + print("Dimmer Radiateur grenier="..tostring(consigne)) + if consigne <= 0 or otherdevices['RadiateurGrenier'] == "Off" then + -- command = 'curl -m 3 "http://192.168.177.240/stop"' + command = 'curl -m 3 "http://192.168.197.193/stop"' + else + -- command = 'curl -m 3 "http://192.168.177.240/exact?value=' .. tostring(consigne * 7).. '"' + command = 'curl -m 3 "http://192.168.197.193/exact?value=' .. tostring(consigne * 3.5).. '"' + end + callExternal(command) + end + +-- ================================================================== +-- INTENSITE_GENERALE +-- ================================================================== +--if (devicechanged['CONSOMMATION_GENERALE']) then +function calcul() + --local tab = getValuesInTab('Oregon_Conso') + --debug("Conso "..otherdevices['Oregon_Conso']) + --values = split(otherdevices['Oregon_Conso'], ";") + --if (tonumber(values[1]) < 0) then + -- if (tonumber(values[1]) == -0.1) then + -- watt = - tonumber(values[2]) + -- else + -- watt = tonumber(values[1]) * 100 - tonumber(values[2]) + -- end + --else + -- watt = (tonumber(values[1]) * 100 + tonumber(values[2])) --/ 1.42 + --end + values2 = split(otherdevices['CONSOMMATION_GENERALE'], ";") + print("NRJ Solaire CONSOMMATION_GENERALE tabs "..otherdevices['CONSOMMATION_GENERALE']) + + watt = tonumber(values2[1]) + for deviceName,deviceValue in pairs(devicechanged) do + if deviceName=="CONSOMMATION_GENERALE_Utility" then + watt = deviceValue + end + + debug ("Device based event fired on '"..deviceName.."', value '"..tostring(deviceValue).."'"); + end + + debug("Conso "..tostring(watt)) + + --debug("mesure"..otherdevices['INTENSITE_GENERALE']) + amp = watt / 230 --math.max(0,round(otherdevices['INTENSITE_GENERALE'],3) - 0.54) * 7 / 8 + + watt_conso = watt --* 0.9459 + updatenum('INTENSITE_GENERALE', amp) + + debug("consommation Amp="..tostring(amp).." conso="..tostring(watt_conso)) + --updatenum('CONSOMMATION_GENERALE', round(watt_conso,0)) + + local tab = getValuesInTab('SolaireProduction') + local watt_solaire = tonumber(tab[1]) + local watt_solaire_jour = otherdevices_svalues['SolaireProduction'] + if watt_solaire == nil then + watt_solaire = 0 + end + + debug("Suivi "..tostring(watt_conso - watt_solaire)) + if (minutes%5 == 0 and secondes < 8) then + date = annee..'-'..mois..'-'..jour_s + + counter_conso = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select counter from Meter_Calendar where DeviceRowID='.. + otherdevices_idx['Consommation_Apparente']..' order by Date desc limit 1;"') + counter_conso=tonumber(counter_conso) or 0 + debug('counter_conso='..counter_conso) + + value_conso = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select Value from Meter where DeviceRowID=='.. + otherdevices_idx['Consommation_Apparente']..' order by Date desc limit 1;"') + value_conso=tonumber(value_conso) or 0 + debug('value_conso='..value_conso) + + + counter_solar = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select counter from Meter_Calendar where DeviceRowID='.. + otherdevices_idx['SolaireProduction']..' order by Date desc limit 1;"') + counter_solar=tonumber(counter_solar) or 0 + debug('counter_solar='..counter_solar) + + value_solar = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select Value from Meter where DeviceRowID=='.. + otherdevices_idx['SolaireProduction']..' order by Date desc limit 1;"') + value_solar=tonumber(value_solar) or 0 + debug('value_solar='..value_solar) + + counter_injection = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select counter from Meter_Calendar where DeviceRowID='.. + otherdevices_idx['INJECTION']..' order by Date desc limit 1;"') + counter_injection=tonumber(counter_injection) or 0 + debug('counter_injection='..counter_injection) + + value_injection = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select Value from Meter where DeviceRowID=='.. + otherdevices_idx['INJECTION']..' order by Date desc limit 1;"') + value_injection=tonumber(value_injection) or 0 + debug('value_injection='..value_injection) + + + counter_radiateur = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select counter from Meter_Calendar where DeviceRowID='.. + otherdevices_idx['Injection_Radiateur']..' order by Date desc limit 1;"') + counter_radiateur=tonumber(counter_radiateur) or 0 + debug('counter_radiateur='..counter_radiateur) + + value_radiateur = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select Value from Meter where DeviceRowID=='.. + otherdevices_idx['Injection_Radiateur']..' order by Date desc limit 1;"') + value_radiateur=tonumber(value_radiateur) or 0 + debug('value_radiateur='..value_radiateur) + + + cumul_solar = value_solar - counter_solar + cumul_injection = value_injection - counter_injection + consommation = value_conso - counter_conso + cumul_radiateur = value_radiateur - counter_radiateur + + debug('conso='..consommation) + debug('cumul_solar='..cumul_solar) + debug('cumul_injection='..cumul_injection) + debug('cumul_radiateur='..cumul_radiateur) + + if (cumul_solar > 0) then + debug("auto consommation="..tostring( + round((100 * (cumul_solar - cumul_injection) / cumul_solar),1)) + ) + commandArray['AUTO_CONSOMMATION'] = otherdevices_idx['AUTO_CONSOMMATION'] ..'|0|' .. tostring( + round((100 * (cumul_solar - cumul_injection) / cumul_solar),1) + ) + updatenum('AUTO_CONSOMMATION', round((100 * (cumul_solar - cumul_injection) / cumul_solar),1) ) + + end + + if (consommation > 0) then + debug("auto production="..tostring(100 * cumul_solar / (cumul_solar + consommation))) + updatenum('AUTO_PRODUCTION', round(100 * cumul_solar / (cumul_solar + consommation),1)) + + end + updatenum('COUVERTURE', round(100 * value_solar / (value_conso + value_solar),1)) + + + if (cumul_solar > 0) then + updatenum('Consommation_Efficace', round(100 *((cumul_solar - cumul_radiateur - cumul_injection) / cumul_solar), 1)) + else + updatenum('Consommation_Efficace', 0) + end + end + +end + +if (devicechanged['Mesure_Courant']) then + print('NRJ Mesure_Courant '..otherdevices['Mesure_Courant']) + values2 = split(otherdevices['Mesure_Courant'], ";") + debug("Solaire Mesure courant tabs ") --..otherdevices['Mesure_Courant']) + + + watt = tonumber(values2[1]) + if (watt > 1600) then + watt = 0; + end + for deviceName,deviceValue in pairs(devicechanged) do + if deviceName=="Mesure_Courant_Utility" then + watt = deviceValue + end + + debug ("Device based event fired on '"..deviceName.."', value '"..tostring(deviceValue).."'"); + end + print("NRJ Solaire Mesure courant "..tostring(watt)) + + --updatenum('SolaireIntensite', round(watt / 230,3)) + --updatenum('INTENSITE_GENERALE', round(watt / 230,3)) + watt = math.abs(watt) --- 56 + --if (watt < 0 or (heures <= 7 or heures >= 21)) then + -- watt = 0 + --end + + --debug("Intensite solaire "..devicechanged['SolaireIntensite']) + amp = math.abs(watt / 230); --math.max(0, round(otherdevices['SolaireIntensite'],3) - 0.54) *1.18 + updatenum('SolaireIntensite', amp) + + print("NRJ # 2 # production amp="..tostring(amp).." watt="..tostring(watt)) + --debug("NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN") + if (watt == nil or watt == "NAN") then + watt = 0 + end + + updatenum('SolaireProduction', round(watt,1)) + + watt_solaire = math.abs(watt) + local tab = getValuesInTab('CONSOMMATION_GENERALE') + local watt_conso = tonumber(tab[1]) + local tab_r = getValuesInTab('Consommation_Apparente') + local watt_reel = tonumber(tab_r[1]) + if (watt_reel > 0) then + updatenum('CONSOMMATION_GENERALE', watt_reel) + if watt_solaire > 0 then + updatenum('COUVERTURE_INSTANTANEE', round(100 * (watt_solaire / (watt_solaire + watt_reel)), 1)) + else + updatenum('COUVERTURE_INSTANTANEE', 0) + end + + else + updatenum('COUVERTURE_INSTANTANEE', 100) + updatenum('CONSOMMATION_GENERALE', 0) + end + calcul() +end + +if (devicechanged['SolaireProduction']) then + +end + +if (devicechanged['Consommation_Apparente']) then + print("NRJ Consommation_Apparente ================================================") + + values2 = split(otherdevices['Consommation_Apparente'], ";") + watt = tonumber(values2[1]) + + for deviceName,deviceValue in pairs(devicechanged) do + if deviceName=="Consommation_Apparente_Utility" then + -- watt = deviceValue + watt = round(deviceValue, 2) + debug ("Device based event fired on '"..deviceName.."', value "..tostring(round(deviceValue, 2))); + + end + + -- debug ("Device based event fired on '"..deviceName.."', value "..tostring(tonumber(deviceValue))); + end + + debug("Solaire Consommation_Apparente "..tostring(watt)) + + values = split(otherdevices['SolaireProduction'], ";") + --debug("Solaire production "..otherdevices['SolaireProduction']) + + watt_solaire = values[1] + + values2 = split(otherdevices['Mesure_Courant'], ";") + --debug("Solaire production mesure courant "..otherdevices['Mesure_Courant']) + + watt_solaire = values[1] --+ values2[1] + if watt_solaire == "NAN" then + watt_solaire = "0" + end + + injection = split(otherdevices['INJECTION'], ";") + debug(injection[1]) + + local debut_injection = - 7 + local fin_injection = 7 + + local currentTemp = getTemperatureFromDevice('Bureau') + + + -- -------------------------------------------------------- + -- Gestion batterie + -- -------------------------------------------------------- + local watt_a_enlever = gestionBatterie("batterie") + --watt = watt - watt_a_enlever -- Charge batterie + + -- ------------------------------------------------------- + + debug("Solaire production temperature Exterieur_Cellier "..tostring(currentTemp).." "..tostring(watt_solaire)) + if disable_radiateur == false then + command = 'curl -s -m 3 "http://192.168.125.11"|grep "

"|awk -F">" \'{print $2}\'|awk -F"<" \'{print $1}\'' + result = callExternal(command) + local radiateur = tonumber(result) * (PUISSANCE_DELESTAGE / 100) + local to_inject = math.abs(watt) -- watt_a_enlever -- tonumber(result) * (PUISSANCE_DELESTAGE / 100) + local quick_value = math.floor(0.5 * to_inject / (PUISSANCE_DELESTAGE / 100)) + print("quick_value result niveau d'injection= "..radiateur ..' to inject='..tostring(to_inject)..' quick='..tostring(quick_value)..' watt='..tostring(watt)..' a_enlever='..tostring(watt_a_enlever)) + --if (otherdevices['InjectionBatterie'] == 'On') then + -- command = 'curl -m 3 "http://192.168.125.11/stop"' + -- callExternal(command) + -- updatenum("Injection_Radiateur", 0) + --else + if result == 0 or result == "" or result == nil or result == "NAN" then + result = 0 + end + if (watt < debut_injection) then + print("quick_value plus="..tostring(quick_value).." conso="..tostring(watt)) + if (quick_value > 0) then + command = 'curl -m 3 "http://192.168.125.11/plus?value=' .. tostring(quick_value).. '"' + callExternal(command) + updatenum("Injection_Radiateur", radiateur + to_inject) + else + print("quick_value reset radiateur") + --command = 'curl -m 3 "http://192.168.125.11/stop"' + --callExternal(command) + --updatenum("Injection_Radiateur", 0) + end + else + if (watt > fin_injection) then + print("quick_value minus="..tostring(quick_value).." conso="..tostring(watt)) + command = 'curl -m 3 "http://192.168.125.11/minus?value=' .. tostring(quick_value).. '"' + callExternal(command) + updatenum("Injection_Radiateur", radiateur - to_inject) + end + end + --end + + else + updatenum("Injection_Radiateur", 0) + end + + if result == 0 or result == "" or result == nil or result == "NAN" then + print("result nil value") + updatenum('TOTAL_AUTOCONSOMMATION', 0) + else + if (tonumber(result) == 1) then + commandArray['Dimmer'] = 'Set Level: 30' + result=0 + end + local injection_radiateur = tonumber(result) * PUISSANCE_DELESTAGE / 100 + updatenum('Injection_Radiateur', injection_radiateur) + updatenum('TOTAL_AUTOCONSOMMATION', round(watt_solaire - injection[1] - math.abs(injection_radiateur), 0)) + end + + -- ======================================================================== + + if (watt < 0) then + debug("Watt injection "..watt) + + updatenum('INJECTION', - round(watt,0)) + updatenum('TOTAL_INJECTION', - round(watt,0)) + else + updatenum('INJECTION', 0) + updatenum('TOTAL_INJECTION', 0) + end + + -- ========================================================= + + --Calculate what the house is consuming + -- Get current date & time + t1 = os.time() + local currentDate = os.date("*t"); -- sets up currentDate.[table] + -- (currentDate.year [full], .month [1-12], .day [1-31], .hour [0-23], .min [0-59], .sec [0-59], .wday [0-6 {Sun-Sat}]) + sCurrentTime = currentDate.year .. "-" .. currentDate.month .. "-" .. currentDate.day .. " " .. currentDate.hour .. ":" .. currentDate.min .. ":" .. currentDate.sec + + counter_solar = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select counter from Meter_Calendar where DeviceRowID='.. + otherdevices_idx['SolaireProduction']..' order by Date desc limit 1;"') + counter_solar=tonumber(counter_solar) or 0 + debug('counter_solar='..counter_solar) + + value_solar = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select Value from Meter where DeviceRowID=='.. + otherdevices_idx['SolaireProduction']..' order by Date desc limit 1;"') + value_solar=tonumber(value_solar) or 0 + debug('value_solar='..value_solar) + + + --------------------------------------------------------------------------------------- + -- Solaire 2 + date = annee..'-'..mois..'-'..jour_s + + counter_solar2 = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select counter from Meter_Calendar where DeviceRowID='.. + otherdevices_idx['Mesure_Courant'].. + ' and date like "' .. date ..'%"'.. + ' order by Date desc limit 1;"') + counter_solar2=tonumber(counter_solar2) or 0 + debug('counter_solar2='..counter_solar2) + + value_solar2 = os.capture('sqlite3 '..'/opt/domoticz/domoticz.db'..' " select Value from Meter where DeviceRowID=='.. + otherdevices_idx['Mesure_Courant'].. + ' and date like "' .. date ..'%"'.. + ' order by Date desc limit 1;"') + value_solar2=tonumber(value_solar2) or 0 + debug('value_solar2='..value_solar2) + + -------------------------------------------------------------------------------------- + watt_p1 = getConsommationHP(1123) or 0 + watt_p2 = getConsommationHC(1123) or 0 + + values_batterie = split(otherdevices['BatterieInjection'], ";") + + print('BatterieInjection='..otherdevices['BatterieInjection']..' '..values_batterie[1]..' '..tostring(watt_solaire)) + + local cmd = '1135|0|' + --USAGE1= energy usage meter tariff 1, This is an incrementing counter + --USAGE2= energy usage meter tariff 2, This is an incrementing counter + --RETURN1= energy return meter tariff 1, This is an incrementing counter + --RETURN2= energy return meter tariff 2, This is an incrementing counter + --CONS= actual usage power (Watt) + --PROD= actual return power (Watt) + .. tostring(math.floor(watt_p1)) .. ';' + .. tostring(math.floor(watt_p2)) .. ';' + -- + value_solar2 - counter_solar2 + .. tostring(math.floor(value_solar - counter_solar + value_solar2 - counter_solar2)) .. ';' + .. '0;' + .. tostring(math.floor(math.max(0,watt)) + watt_solaire + tonumber(values_batterie[1])).. ';' + .. tostring(math.floor(watt_solaire + tonumber(values_batterie[1]))) --math.floor(ConsumoEnergyBalance / 1000)) --round(watt,0)) + + debug('Consommation_Reelle_2 '..cmd) + if heures == 23 and minutes == 59 and secondes >= 45 then + -- ignored + else + table.insert (commandArray, { ['UpdateDevice'] = cmd } ) + end + if heures == 00 and minutes == 05 and secondes <= 10 then + deleteWrongData(1135) + end + debug('when light=' .. tostring(whenLight())) + + -- ========================================================= + + local cmd = '1136|0|' + --USAGE1= energy usage meter tariff 1, This is an incrementing counter + --USAGE2= energy usage meter tariff 2, This is an incrementing counter + --RETURN1= energy return meter tariff 1, This is an incrementing counter + --RETURN2= energy return meter tariff 2, This is an incrementing counter + --CONS= actual usage power (Watt) + --PROD= actual return power (Watt) + .. '0;' + .. '0;' + .. '0;' + .. '0;' + .. tostring(math.floor(math.max(0,watt))).. ';' + .. '0' --math.floor(ConsumoEnergyBalance / 1000)) --round(watt,0)) + table.insert (commandArray, { ['UpdateDevice'] = cmd } ) + updatenum('Non_Couvert_2', math.floor(math.max(0,watt))) + + -- ========================================================= + +end + +-- +return commandArray + diff --git a/lua/script_device_General.lua b/lua/script_device_General.lua new file mode 100755 index 0000000..eb2bd07 --- /dev/null +++ b/lua/script_device_General.lua @@ -0,0 +1,229 @@ +require "scripts/lua/functions" + +commandArray = {} + +-- ------------------------------------------------------------------------------ +--recupere les minutes +-- ------------------------------------------------------------------------------ +time=os.time() +minutes=tonumber(os.date('%M',time)) +jour=tonumber(os.date('%w',time)) +quantieme=tonumber(os.date('%j',time)) +heures=tonumber(os.date('%H',time)) +heurmin= heures * 60 + minutes + +extinction = uservariables['HEURE_EXTINCTION_FEUX'] + +-- ------------------------------------------------------------------------------ +-- Test check +-- ------------------------------------------------------------------------------ +-- List all otherdevices states for debugging: +-- for i, v in pairs(otherdevices) do debug(i..' '..v) end +-- List all otherdevices svalues for debugging: +-- for i, v in pairs(otherdevices_svalues) do debug('svalues '..i..' '..v) end + +-- ------------------------------------------------------------------------------ +-- Pollens tous les lundis +-- ------------------------------------------------------------------------------ +if (jour == 1 and devicechanged['Pollens']) then + debug("Nouveau bulletin pollens") + + commandArray['SendNotification']='Pollens#Nouveau bulletin pollen http://www.pollens.fr/docs/vigilance.html#0' +end + +-- ------------------------------------------------------------------------------ +-- Derniere détection +-- ------------------------------------------------------------------------------ +if devicechanged['Detecteur Salon'] or devicechanged['Detecteur Bureau'] then + commandArray['Variable:DerniereDetection'] = tostring(heures)..":"..tostring(minutes) + debug("DerniereDetection"..tostring(heures)..":"..tostring(minutes)) +end + +-- ------------------------------------------------------------------------------ +-- Température extérieure a changé, mise à jour du chauffage central +-- ------------------------------------------------------------------------------ +if devicechanged['BarometreLaGacilly'] then + local variation = variationTemp('BarometreLaGacilly') + + --if (minutes%30==0) then + --local variationBarometer = variationPressure('BarometreLaGacilly', 30) + --print("variationBarometer="..tostring(variationBarometer)) + local tempExt = getTemperatureFromDevice('BarometreLaGacilly') + local humidityExt = getHumidityFromDevice('BarometreLaGacilly') + --print(split(otherdevices_svalues['BarometreLaGacilly'],";")[1]); + local consigne = 13 -- tonumber(otherdevices_svalues['ConsigneChauffageGeneral']) + debug (otherdevices_svalues['BarometreLaGacilly']..' Consigne='..otherdevices_svalues['ConsigneChauffageGeneral']..' TempExt='..tostring(tempExt)..' humidityExt='..tostring(humidityExt)) + + if heures == 23 and minutes == 00 then + if tempExt < consigne and (quantieme < 92 or quantieme > 275) then + switchIfNeeded('ChauffageGeneral','On') + end + if tempExt >= consigne then + switchIfNeeded('ChauffageGeneral','Off') + end + end + + if humidityExt > 65 then + switchIfNeeded('Deshumidificateur','On') + else + if humidityExt < 60 then + switchIfNeeded('Deshumidificateur','Off') + end + end + + debug("Retour variation="..tostring(variation).." switch="..'BarometreLaGacilly tempExt='..tostring(tempExt)) + --end + +end + +-- ------------------------------------------------------------------------------ +-- Test suivi consommation électrique +-- ------------------------------------------------------------------------------ +--debug(otherdevices['ConsoCapteurHC']) +--debug("ConsocapteurHP="..otherdevices_svalues['ConsoCapteurHP']) + +if devicechanged['Capteur électricité'] then + debug("Electricité a changé") + + local val + local val2 + val, val2 = otherdevices_svalues['Capteur électricité']:match("([^;]+);([^;]+)") + val = tonumber(val) + debug(val) + --debug('#### HC '..otherdevices['ConsoCapteurHC']) + --debug('#### HP '..otherdevices['ConsoCapteurHP']) + if val > 2200 or val == nil then + debug("Reception de données incohérentes pour la consommation électrique "..tostring(val)) + else + val = val - 50 + if uservariables['HeuresCreuses'] == 'On' then + + -- Recuperation des valeurs du compteur global + local consoCumule + local consoInstant + consoInstant, consoCumule = otherdevices_svalues['ConsoCapteurHC']:match("([^;]+);([^;]+)") + consoInstant = tonumber(consoInstant) + consoCumule = tonumber(consoCumule) + + debug('Conso Instant = '..tostring(consoInstant)..' / Conso Cumule = '..tostring(consoCumule)..' ') + + local timeLast = lastUpdateOfDevice('ConsoCapteurHC') + + local joules = val * timeLast -- Puissance en W * second = Joule + + local wattH = joules / 3600 + + if (consoCumule == nil) then consoCumule = 0 end + if (val < 0) then wattH = 0 end + commandArray['UpdateDevice'] = '197|0|'..tostring(wattH)..';'..tostring(consoCumule + wattH) + + debug("Ajout en heures creuses wattH "..tostring(wattH)..'; total '..tostring(consoCumule + wattH)) + else + -- Recuperation des valeurs du compteur global + local consoCumule + local consoInstant + consoInstant, consoCumule = otherdevices_svalues['ConsoCapteurHP']:match("([^;]+);([^;]+)") + consoInstant = tonumber(consoInstant) + consoCumule = tonumber(consoCumule) + + debug('Conso Instant = '..tostring(consoInstant)..' / Conso Cumule = '..tostring(consoCumule)..' ') + + --local current = tonumber(otherdevices_svalues['ConsoCapteurHP']) + --if current == nil then current = 0 end + + local timeLast = lastUpdateOfDevice('ConsoCapteurHP') + + local joules = val * timeLast -- Puissance en W * second = Joule + + local wattH = joules / 3600 + if (val < 0) then wattH = 0 end + commandArray['UpdateDevice'] = '196|0|'..tostring(wattH)..';'..tostring(consoCumule + wattH) + + debug("Ajout en heures pleines wattH "..tostring(wattH)..'; total '..tostring(consoCumule + wattH)) + end + end +end + +-- ------------------------------------------------------------------------------ +-- Mode vacances +-- ------------------------------------------------------------------------------ +-- ------------------------------------------------------------------------------ +-- Envoi de notification +-- ------------------------------------------------------------------------------ +-- Vacances +if devicechanged['Vacances'] then + debug("Mode vacances a change") + commandArray['SendNotification']='Mode vacances#Le mode vacances a ete modifie#0' + + if otherdevices['Vacances'] == 'On' then + -- non on conserve internet switchIfNeeded('PriseInternet', 'Off') + switchIfNeeded('Lampe_Halogene', 'Off') + switchIfNeeded('Lampe_Buffet', 'Off') + switchIfNeeded('Lampe_Tele', 'Off') + switchIfNeeded('SonoJasper', 'Off') + + switchOffRadiateur('RadiateurManon') + switchOffRadiateur('RadiateurTheo') + switchOffRadiateur('RadiateurBureau') + switchOffRadiateur('RadiateurChambre') + switchOffRadiateur('RadiateurCuisine') + switchOffRadiateur('RadiateurMilieu') + switchOffRadiateur('RadiateurCheminee') + end +end + + +-- ------------------------------------------------------------------------------ +-- Plus d'internet on redémarre +-- ------------------------------------------------------------------------------ +if --otherdevices['Vacances'] == 'Off' and + devicechanged['Internet'] and otherdevices['Internet'] == 'Off' then + commandArray['PriseInternet'] = 'Off' + sleep(10) + commandArray['PriseInternet'] = 'On' +end + +-- ------------------------------------------------------------------------------ +-- Absence famille mais présence moi +-- ------------------------------------------------------------------------------ +if otherdevices['Vacances'] == 'Off' and devicechanged['AbsenceFamille'] then + if otherdevices['AbsenceFamille'] == 'Off' then + switchOffRadiateur('RadiateurTheo') + switchOffRadiateur('RadiateurChambre') + else + switchOnRadiateur('RadiateurTheo') + switchOnRadiateur('RadiateurChambre') + end +end +-- ------------------------------------------------------------------------------ +-- Determination de l'augmentation de la temperature exterieure +-- ------------------------------------------------------------------------------ +if devicechanged['BarometreLaGacilly'] then + print("--------------TemperatureLaGacilly--------------------------------") + + local variation, time = getVariation('BarometreLaGacilly') + + local augmentation = variation * 60 / time -- ° par heure + + print("Retour augmentation="..tostring(augmentation)) + + commandArray['Variable:AugmentationTempExterieure'] = tostring(augmentation) + + print("------------------------------------------------------------------") + + --local currentTemp = tonumber(otherdevices_svalues['Bureau'] + local tempExt = getTemperatureFromDevice('BarometreLaGacilly') + + debug("-------------- Ventilo Bureau------------------- "..tostring(tempExt)) + + + if (tempExt < 8.5) then + switchOn('VentilateurBureau') + else + switchOff('VentilateurBureau') + end + +end + + +return commandArray diff --git a/lua/script_device_Presence.lua b/lua/script_device_Presence.lua new file mode 100755 index 0000000..7a2c9b0 --- /dev/null +++ b/lua/script_device_Presence.lua @@ -0,0 +1,37 @@ +-- demo device script +-- script names have three name components: script_trigger_name.lua +-- trigger can be 'time' or 'device', name can be any string +-- domoticz will execute all time and device triggers when the relevant trigger occurs +-- +-- copy this script and change the "name" part, all scripts named "demo" are ignored. +-- +-- Make sure the encoding is UTF8 of the file +-- +-- ingests tables: devicechanged, otherdevices,otherdevices_svalues +-- +-- device changed contains state and svalues for the device that changed. +-- devicechanged['yourdevicename']=state +-- devicechanged['svalues']=svalues string +-- +-- otherdevices and otherdevices_svalues are arrays for all devices: +-- otherdevices['yourotherdevicename']="On" +-- otherdevices_svalues['yourotherthermometer'] = string of svalues +-- +-- Based on your logic, fill the commandArray with device commands. Device name is case sensitive. +-- +-- Always, and I repeat ALWAYS start by checking for the state of the changed device. +-- If you would only specify commandArray['AnotherDevice']='On', every device trigger will switch AnotherDevice on, which will trigger a device event, which will switch AnotherDevice on, etc. +-- +-- The print command will output lua print statements to the domoticz log for debugging. +-- List all otherdevices states for debugging: +-- for i, v in pairs(otherdevices) do print(i, v) end +-- List all otherdevices svalues for debugging: +-- for i, v in pairs(otherdevices_svalues) do print(i, v) end +-- +-- TBD: nice time example, for instance get temp from svalue string, if time is past 22.00 and before 00:00 and temp is bloody hot turn on fan. + +commandArray = {} +if (devicechanged['Presence Forcee'] == 'On' and otherdevices['Presence'] == 'Off') then + commandArray['Presence']='On' +end +return commandArray diff --git a/lua/script_device_Radiateur.lua b/lua/script_device_Radiateur.lua new file mode 100755 index 0000000..9ff8243 --- /dev/null +++ b/lua/script_device_Radiateur.lua @@ -0,0 +1,485 @@ +require "scripts/lua/functions" + +commandArray = {} + +--local switch = 'VoletCuisine' + +-- ------------------------------------------------------------------------------ +--recupere les minutes +-- ------------------------------------------------------------------------------ +time = os.time() +minutes = tonumber(os.date('%M',time)) +jour = tonumber(os.date('%w',time)) +heures = tonumber(os.date('%H',time)) +heurmin = heures * 60 + minutes + +function callExternal(command) + local handle = io.popen(command) + local result = handle:read("*a") + handle:close() + --debug("Commande = "..command.." "..result) + return result +end + +-- ------------------------------------------------------------------------------ +-- Test temperature radiateur chambres +-- ------------------------------------------------------------------------------ +function gestionRadiateurInv( switchTemp, switchRadiateur, consigne) + local intervalle = tonumber(uservariables['Intervalle_Chauffe']) + + --if (minutes % intervalle ~= 0) then + --return + --end + + local last = lastUpdateOfDevice(switchRadiateur) + + local local_delai = delai + + debug("--------------"..switchRadiateur.."-----------------------------------") + debug(tostring(switchRadiateur).." local_delai="..tostring(local_delai).." last="..tostring(last)..' Chauffage='..otherdevices[switchRadiateur]) + debug("------------------------------------------------------------") + + local currentTemp = tonumber(otherdevices_svalues[switchTemp]) + + local delta = 0.2 + + local tempAbsence = tonumber(otherdevices_svalues['ConsigneAbsence']) + + local variation = variationTemp2(switchTemp, 10) -- variation des 10 dernières minutes + + local variationExt = uservariables['AugmentationTempExterieure'] + + local augmentation = variation * 60 / 10 --time -- ° par heure + + local ecart = consigne - currentTemp + + local estimation = 0.0 + if (augmentation > 0 and ecart > 0) then + estimation = 60 * ecart / augmentation + end + + print("GR Retour augmentation="..tostring(augmentation).." ecart="..tostring(ecart)..'°C Estimation='..tostring(estimation).." minutes variationExt="..tostring(variationExt).."°C / heure") + +--2016-02-27 20:08:59.864 LUA: local_delai=180 last=37 +--2016-02-27 20:08:59.918 LUA: Retour variation=0.3 switch=RadiateurManon +--2016-02-27 20:08:59.918 LUA: CHECK Temperature Variation=0.3 switch=RadiateurManon currentTemp=18.3 tempAbsence=16 consigne=18.5 + + print("GR Retour variation="..tostring(variation).." switch="..switchRadiateur..' lastUpdate='..tostring(last)) + debug('CHECK Temperature Variation='..tostring(variation)..' switch='..switchRadiateur..' currentTemp='..tostring(currentTemp).. ' tempAbsence='..tostring(tempAbsence)..' consigne='..tostring(consigne)) + -- if otherdevices['ChauffageGeneral'] == 'Off' then + -- if (minutes%5 == 0) then + -- if (currentTemp >= consigne + delta) then + -- switchOn(switchRadiateur) + -- end + -- debug("Radiateur ="..switchRadiateur.." Retour sans rien faire. ChauffageGeneral Eteint.") + -- end + -- return + -- end + if last < local_delai then + debug("Radiateur ="..switchRadiateur.." Retour sans rien faire. local_delai non atteint.") + return + end + -- Periode de vacances ou absence ==> hors gel + if (otherdevices['Vacances'] == 'On' or otherdevices['AbsenceFamille'] == 'On') then + if (currentTemp > 14) then + switchIfNeeded(switchRadiateur,"On") + --commandArray[switchRadiateur]='Off' + else + if variation <= 0 then + --commandArray[switchRadiateur]='On' + switchIfNeeded(switchRadiateur,"Off") + end + end + print("GR "..tostring(switchRadiateur)..' Temperature chambre : Vacances -> ' ..otherdevices_svalues[switchTemp]..' switch='..switchRadiateur) + else + print("GR "..tostring(switchRadiateur)..' Temperature: Presence -> ' ..otherdevices_svalues[switchTemp]..' '..josdGetJourSemaine(jour)) + -- Température non atteinte + if (currentTemp < consigne) then + if variation <= 0.0 then + switchIfNeeded(switchRadiateur,"Off") + debug("Demande chauffe : "..tostring(currentTemp).." / "..tostring(consigne).." Variation="..tostring(variation)) + else + -- Dépassement prévu dans le local_delai on coupe + if (estimation > 0 and estimation <= local_delai / 60 ) then + switchIfNeeded(switchRadiateur,"On") + debug("Arrêt chauffage : Température sera atteinte dans le local_delai "..tostring(estimation).." Minutes") + else + if estimation > 60 then + switchIfNeeded(switchRadiateur,"Off") + debug("Demande chauffe dela trop long : "..tostring(currentTemp).." / "..tostring(consigne).." Variation="..tostring(variation)) + else + debug("Aucune action. Chauffage en-cours."..tostring(currentTemp).." / "..tostring(consigne).." Variation="..tostring(variation)) + end + end + end + -- Température dépassée + else + -- Température supérieure + if (currentTemp >= consigne + delta or (estimation > 0 and estimation <= local_delai / 60 )) then + if (consigne == consigneAbsence) then + -- rien + if (variation > 0) then + switchIfNeeded(switchRadiateur,"On") + debug("Demande arrêt. Température dépassée et augmente.") + else + debug("Aucune consigne. Température dépassée et diminue.") + end + else + if (variation > 0) then + if (variationExt <= 0) then + switchIfNeeded(switchRadiateur,"On") + debug("Demande arrêt. Température dépassée.") + else + switchIfNeeded(switchRadiateur,"On") + debug("Aucune action. Augmentation due à température extérieure.") + end + else + -- switchIfNeeded(switchRadiateur,"On") + end + end + else + -- Augmentation de la température non due à l'augmentation extérieure + if (variation > 0) then + -- Pas d'augmentation extérieure + if (variationExt <= 0) then + switchIfNeeded(switchRadiateur,"On") + debug("Demande arrêt. Température atteinte et continue d'augmenter.") + else + switchIfNeeded(switchRadiateur,"On") + debug("Aucune action. Augmentation due à température extérieure.") + end + else + -- Températue en baisse pas nécessaire d'envoyer + switchIfNeeded(switchRadiateur,"On") + debug("Aucune action. Temperature atteinte et pas d'augmentation. "..tostring(currentTemp).." / "..tostring(consigne).." Variation="..tostring(variation)) + end + end + end + end + debug("------------------------------------------------------------") +end +-- ------------------------------------------------------------------------------ +-- Test temperature radiateur chambres +-- ------------------------------------------------------------------------------ +function gestionRadiateur( switchTemp, switchRadiateur, consigne) + local intervalle = tonumber(uservariables['Intervalle_Chauffe']) + +-- if (minutes % intervalle ~= 0) or switchRadiateur == "RadiateurGrenier" then +-- return +-- end + local chauffe_eau = tonumber(split(otherdevices['Chauffe_Eau'], ";")[1]) + local currentTemp = getTemperatureFromDevice(switchTemp) + + local last = lastUpdateOfDevice(switchRadiateur) + local local_delai = delai + if switchRadiateur == "RadiateurGrenier" then + local_delai = 60 + end + + print("GR --------------"..switchRadiateur.."-----------------------------------") + values2 = split(otherdevices['CONSOMMATION_GENERALE'], ";") + print("GR Dans Radiateur CONSOMMATION_GENERALE tabs "..otherdevices['CONSOMMATION_GENERALE']) + print("GR "..tostring(switchRadiateur).." local_delai="..tostring(local_delai).." last="..tostring(last)..' Chauffage='..otherdevices[switchRadiateur] .. " currentTemp="..tostring(currentTemp) ) + + if last < local_delai then + print("GR Radiateur ="..switchRadiateur.." Retour sans rien faire. local_delai non atteint.") + return + end + + watt = tonumber(values2[1]) + if watt > 8000 then + if otherdevices["RadiateurBureau"] == 'On' then + print("GR "..tostring(switchRadiateur).." Dans Radiateur Haute consommation arrêt bureau") + switchOffRadiateur("RadiateurBureau") + elseif otherdevices["RadiateurBureau"] == 'On' then + print("GR "..tostring(switchRadiateur).." Dans Radiateur Haute consommation arrêt porte salon") + switchOffRadiateur("RadiateurPorteSalon") + elseif otherdevices["RadiateurCuisine"] == 'On' then + print("GR "..tostring(switchRadiateur).." Dans Radiateur Haute consommation arrêt cuisine") + switchOffRadiateur("RadiateurCuisine") + elseif otherdevices["RadiateurCheminee"] == 'On' then + print("GR "..tostring(switchRadiateur).." Dans Radiateur Haute consommation arrêt Cheminee") + switchOffRadiateur("RadiateurCheminee") + elseif otherdevices["RadiateurMilieu"] == 'On' then + print("GR "..tostring(switchRadiateur).." Dans Radiateur Haute consommation arrêt milieu") + switchOffRadiateur("RadiateurMilieu") + end + end + + + --print("GR ------------------------------------------------------------") + --debug(getTemperatureFromDevice(switchTemp)); + --local currentTemp = tonumber(otherdevices_svalues[switchTemp]) + + + local time_variation = 30 + local delta = 0.2 + + local tempAbsence = tonumber(otherdevices_svalues['ConsigneAbsence']) + + local variation = variationTemp2(switchTemp, time_variation) -- variation des 10 dernières minutes + + local variationExt = uservariables['AugmentationTempExterieure'] + + local augmentation = variation * 60 / time_variation --time -- ° par heure + + local ecart = consigne - currentTemp + + local estimation = 0.0 + if (augmentation > 0 and ecart > 0) then + estimation = 60 * ecart / augmentation + end + + --if (switchRadiateur=="RadiateurCheminee" and augmentation > 1) then + -- arretRadiateursSalon('ChauffageGeneral') + --end + + + print("GR "..tostring(switchRadiateur).." Retour augmentation="..tostring(augmentation).." ecart="..tostring(ecart)..'°C Estimation='..tostring(estimation).." minutes variationExt="..tostring(variationExt).."°C / heure") + +--2016-02-27 20:08:59.864 LUA: local_delai=180 last=37 +--2016-02-27 20:08:59.918 LUA: Retour variation=0.3 switch=RadiateurManon +--2016-02-27 20:08:59.918 LUA: CHECK Temperature Variation=0.3 switch=RadiateurManon currentTemp=18.3 tempAbsence=16 consigne=18.5 + + print("GR "..tostring(switchRadiateur).." Retour variation="..tostring(variation).." switch="..switchRadiateur..' lastUpdate='..tostring(last)) + print("GR "..tostring(switchRadiateur).." Temperature Variation="..tostring(variation)..' switch='..switchRadiateur..' currentTemp='..tostring(currentTemp).. ' tempAbsence='..tostring(tempAbsence)..' consigne='..tostring(consigne)) + + if otherdevices['ChauffageGeneral'] == 'Off' then + if (minutes%5 == 0) then + if (currentTemp >= consigne + delta) then + switchOff(switchRadiateur) + end + debug("ChauffageGeneral Eteint. Demande extinction.") + else + debug("Radiateur ="..switchRadiateur.." Retour sans rien faire. ChauffageGeneral Eteint.") + end + return + end + if (currentTemp >= consigne + 2 * delta) then + print("GR Radiateur ="..switchRadiateur.." arret immediat température > consigne + 2 * delta.") + switchIfNeeded(switchRadiateur,"Off") + return + end + + -- Periode de vacances ou absence ==> hors gel + if (otherdevices['Vacances'] == 'On' or otherdevices['AbsenceFamille'] == 'On') then + if (currentTemp > 14) then + switchIfNeeded(switchRadiateur,"Off") + --commandArray[switchRadiateur]='Off' + else + if variation <= 0 then + --commandArray[switchRadiateur]='On' + switchIfNeeded(switchRadiateur,"On") + end + end + print("GR "..tostring(switchRadiateur)..' Temperature chambre : Vacances -> ' ..otherdevices_svalues[switchTemp]..' switch='..switchRadiateur) + else + print("GR "..tostring(switchRadiateur)..' Temperature: Presence -> ' ..otherdevices_svalues[switchTemp]..' '..josdGetJourSemaine(jour)) + -- Température non atteinte + if (currentTemp < consigne - delta) then + debug('Temperature non atteinte') + if variation <= 0.0 then + -- commandArray[switchRadiateur]='On' + switchIfNeeded(switchRadiateur,"On") + print("GR "..tostring(switchRadiateur).."Demande chauffe : "..tostring(currentTemp).." / "..tostring(consigne).." Variation="..tostring(variation)) + else + --switchIfNeeded(switchRadiateur, 'On') + -- Dépassement prévu dans le local_delai on coupe + if (estimation > 0 and estimation <= local_delai / 60 ) then + --commandArray[switchRadiateur] = 'Off' + switchIfNeeded(switchRadiateur,"Off") + print("GR "..tostring(switchRadiateur).." Arrêt chauffage : Température sera atteinte dans le local_delai "..tostring(estimation).." Minutes") + else + if estimation > 60 then + switchIfNeeded(switchRadiateur,"On") + debug("Demande chauffe dela trop long : "..tostring(currentTemp).." / "..tostring(consigne).." Variation="..tostring(variation)) + else + debug("Aucune action. Chauffage en-cours."..tostring(currentTemp).." / "..tostring(consigne).." Variation="..tostring(variation)) + end + end + end + -- Température dépassée + else + debug('Temperature supérieure') + + -- Température supérieure + if (currentTemp >= consigne + delta or (estimation > 0 and estimation <= local_delai / 60 )) then + if (consigne == consigneAbsence) then + switchIfNeeded(switchRadiateur,"Off") + else + if (variation > 0) then + if (variationExt <= 0) then + switchIfNeeded(switchRadiateur,"Off") + debug("Demande arrêt. Température dépassée.") + else + switchIfNeeded(switchRadiateur,"Off") + debug("Aucune action. Augmentation due à température extérieure.") + end + else + debug('Aucune variation') + + switchIfNeeded(switchRadiateur,"Off") + end + end + else if (currentTemp <= consigne - delta) then + -- Augmentation de la température non due à l'augmentation extérieure + if (variation > 0) then + -- Pas d'augmentation extérieure + if (variationExt <= 0) then + switchIfNeeded(switchRadiateur,"Off") + debug("Demande arrêt. Température atteinte et continue d'augmenter.") + else + switchIfNeeded(switchRadiateur,"Off") + debug("Aucune action. Augmentation due à température extérieure.") + end + else + -- Températue en baisse pas nécessaire d'envoyer + switchIfNeeded(switchRadiateur,"Off") + debug("Aucune action. Temperature atteinte et pas d'augmentation. "..tostring(currentTemp).." / "..tostring(consigne).." Variation="..tostring(variation)) + end + end + end + end + end + debug("------------------------------------------------------------") +end + +-- ------------------------------------------------------------------------------ +-- Test temperature radiateur salon et cuisine +-- ------------------------------------------------------------------------------ +function gestionRadiateurSalon( switchTemp, switchRadiateur, consigne) + local currentTemp = tonumber(otherdevices_svalues[switchTemp]) + local tempAbsence = tonumber(otherdevices_svalues['ConsigneAbsence']) + + if otherdevices['ChauffageGeneral'] == 'Off' then + if (minutes%30 == 0) then + switchOffRadiateur(switchRadiateur) + else + debug("Radiateur ="..switchRadiateur.." Retour sans rien faire. ChauffageGeneral Eteint.") + end + end + -- Periode de vacances ou absence ==> hors gel + if (otherdevices['Vacances'] == 'On' or otherdevices['Presence'] == 'Off') then + if (currentTemp > tempAbsence) then + switchOffRadiateur(switchRadiateur) + else + switchOnRadiateur(switchRadiateur) + end + print("GR "..tostring(switchRadiateur)..' Temperature Salon: Vacances -> ' ..otherdevices_svalues[switchTemp]..' switch='..switchRadiateur) + else + + -- Samedi Dimanche ou jour férié ou mercredi + if (jour == 0 or jour == 6 or josdJourChome() or jour == 3) then + print("GR "..tostring(switchRadiateur)..' Temperature: Presence -> ' ..otherdevices_svalues[switchTemp]..' '..josdGetJourSemaine(jour)) + if (currentTemp < tempAbsence + or (currentTemp <= consigne and heures >= 08 and heures <= 24)) then + switchOnRadiateur(switchRadiateur) + else + switchOffRadiateur(switchRadiateur) + end + else + print("GR "..tostring(switchRadiateur)..' Temperature: Travail -> ' ..otherdevices_svalues[switchTemp]..' '..josdGetJourSemaine(jour)) + if (currentTemp < tempAbsence + or (currentTemp <= (consigne - 1) and heures >= 17) + or (currentTemp <= consigne and heures >= 19 and heures < 23)) then + switchOnRadiateur(switchRadiateur) + else + switchOffRadiateur(switchRadiateur) + end + end + end +end + + +-- ------------------------------------------------------ +-- Arrêt tous les radiateurs +-- ------------------------------------------------------ +if devicechanged['ChauffageGeneral'] then + print("Chauffage General "..otherdevices['ChauffageGeneral']) + if otherdevices['ChauffageGeneral'] == 'Off' then + -- for i = 1, 7 do + for i,radiateur in ipairs(radiateurs) do + print("Chauffage General Arrêt radiateur="..radiateur) + commandArray[radiateur]='Off' + end + end +end + +local saison = uservariables["Saison"] + +if otherdevices['ChauffageGeneral'] == 'On' then + + -- ---------------------------------------------------- + -- Chambre de Manon + -- ------------------------------------------------------ + if devicechanged['ChambreManon'] or devicechanged['ConsigneConfortManon'] or devicechanged['ChauffageGeneral'] + then --or tonumber(lastUpdateOfDevice('ChambreManon')) > 2 * delai then + local consigne = tonumber(otherdevices_svalues['ConsigneConfortManon']) + gestionRadiateur('ChambreManon', 'RadiateurManon', consigne) + end + + -- ------------------------------------------------------ + -- Chambre de Theo + -- ------------------------------------------------------ + if devicechanged['ChambreTheo'] or devicechanged['ConsigneConfortTheo'] or devicechanged['ChauffageGeneral'] + then -- or tonumber(lastUpdateOfDevice('ChambreTheo')) > 2 * delai then + local consigne = tonumber(otherdevices_svalues['ConsigneConfortTheo']) + gestionRadiateur('ChambreTheo', 'RadiateurTheo', consigne) + end + -- ------------------------------------------------------ + -- Chambre parents + -- ------------------------------------------------------ + if devicechanged['Chambre'] or devicechanged['ConsigneConfortChambre'] or devicechanged['ChauffageGeneral'] + then --or tonumber(lastUpdateOfDevice('Chambre')) > 2 * delai then + local consigne = tonumber(otherdevices_svalues['ConsigneConfortChambre']) + gestionRadiateur('Chambre', 'RadiateurChambre', consigne) + end + -- ------------------------------------------------------ + -- Radiateur cuisine + -- ------------------------------------------------------ + if devicechanged['TemperatureCuisine'] or devicechanged['ConsigneConfortSalon'] or devicechanged['ChauffageGeneral'] + then -- or tonumber(lastUpdateOfDevice('TemperatureCuisine')) > 2 * delai then + local consigne = tonumber(otherdevices_svalues['ConsigneConfortSalon']) + gestionRadiateur('TemperatureCuisine', 'RadiateurCuisine', consigne) + end + -- ------------------------------------------------------ + -- Radiateur Cheminee + -- ------------------------------------------------------ + if devicechanged['Cheminee'] or devicechanged['ConsigneConfortSalon'] or devicechanged['ChauffageGeneral'] + then -- or tonumber(lastUpdateOfDevice('Cheminee')) > 2 * delai then + local consigne = tonumber(otherdevices_svalues['ConsigneConfortSalon']) - 1 --0.2 + gestionRadiateur('Cheminee', 'RadiateurCheminee', consigne) + end + -- ------------------------------------------------------ + -- Radiateur Salon + -- ------------------------------------------------------ + if devicechanged['TemperatureSalon'] or devicechanged['ConsigneConfortSalon'] or devicechanged['ChauffageGeneral'] + then -- or tonumber(lastUpdateOfDevice('TemperatureSalon')) > 2 * delai then + local consigne = tonumber(otherdevices_svalues['ConsigneConfortSalon']) + gestionRadiateur('TemperatureSalon', 'RadiateurPorteSalon', consigne) + gestionRadiateur('TemperatureSalon', 'RadiateurMilieu', consigne) + end + + -- ------------------------------------------------------ + -- Radiateur Bureau + -- ------------------------------------------------------ + if devicechanged['Bureau'] or devicechanged['ConsigneConfortBureau'] or devicechanged['ChauffageGeneral'] + then -- or tonumber(lastUpdateOfDevice('Bureau')) > 2 * delai then + local consigne = tonumber(otherdevices_svalues['ConsigneConfortBureau']) + gestionRadiateur('Bureau', 'RadiateurBureau', consigne) + --gestionRadiateur('TemperatureBarometre', 'RadiateurCheminee', consigne) + end + + -- ------------------------------------------------------ + -- Radiateur Grenier + -- ------------------------------------------------------ + if (devicechanged['TemperatureGrenier'] or devicechanged['ConsigneConfortGrenier'] or devicechanged['ChauffageGeneral'] or devicechanged['Force_Grenier']) + then -- or tonumber(lastUpdateOfDevice('TemperatureGrenier')) > 2 * delai then + local consigne = tonumber(otherdevices_svalues['ConsigneConfortGrenier']) + gestionRadiateur('TemperatureGrenier', 'RadiateurGrenierAcova', consigne) + --gestionRadiateur('TemperatureBarometre', 'RadiateurCheminee', consigne) + end + +end + +return commandArray diff --git a/lua/script_device_Vacances.lua b/lua/script_device_Vacances.lua new file mode 100755 index 0000000..08da56d --- /dev/null +++ b/lua/script_device_Vacances.lua @@ -0,0 +1,64 @@ +-- demo device script +-- script names have three name components: script_trigger_name.lua +-- trigger can be 'time' or 'device', name can be any string +-- domoticz will execute all time and device triggers when the relevant trigger occurs +-- +-- copy this script and change the "name" part, all scripts named "demo" are ignored. +-- +-- Make sure the encoding is UTF8 of the file +-- +-- ingests tables: devicechanged, otherdevices,otherdevices_svalues +-- +-- device changed contains state and svalues for the device that changed. +-- devicechanged['yourdevicename']=state +-- devicechanged['svalues']=svalues string +-- +-- otherdevices and otherdevices_svalues are arrays for all devices: +-- otherdevices['yourotherdevicename']="On" +-- otherdevices_svalues['yourotherthermometer'] = string of svalues +-- +-- Based on your logic, fill the commandArray with device commands. Device name is case sensitive. +-- +-- Always, and I repeat ALWAYS start by checking for the state of the changed device. +-- If you would only specify commandArray['AnotherDevice']='On', every device trigger will switch AnotherDevice on, which will trigger a device event, which will switch AnotherDevice on, etc. +-- +-- The print command will output lua print statements to the domoticz log for debugging. +-- List all otherdevices states for debugging: +-- for i, v in pairs(otherdevices) do print(i, v) end +-- List all otherdevices svalues for debugging: +-- for i, v in pairs(otherdevices_svalues) do print(i, v) end +-- +-- TBD: nice time example, for instance get temp from svalue string, if time is past 22.00 and before 00:00 and temp is bloody hot turn on fan. + +--recupere les minutes +time=os.time() +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) + +commandArray = {} +--if (minutes == 0 or minutes == 30) then +-- TBD: nice time example, for instance get temp from svalue string, if time is past 22.00 and before 00:00 and temp is bloody hot turn on fan. + +--recupere les minutes +time=os.time() +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) + +commandArray = {} +if (minutes == 0 or minutes == 30) then + if (devicechanged['Vacances']) then + if otherdevices['Vacances'] == 'On' then + print('Depart en vacances : Actions') + print(' Actions : Arret Volumio et Raspbmc') + print(' Actions : Activation script vacances ') + print(' Actions : Arret chauffage ') + + else + print('Retour de vacances : Actions') + print(' Actions : Arret script vacances ') + print(' Actions : Demarrage chauffage ') + + end + end +end +return commandArray diff --git a/lua/script_device_compteurHC-HP.lua b/lua/script_device_compteurHC-HP.lua new file mode 100755 index 0000000..f784660 --- /dev/null +++ b/lua/script_device_compteurHC-HP.lua @@ -0,0 +1,112 @@ +-- script domoticz/scripts/lua/script_device_compteurHC-HP.lua + +-- Initialisation des variables locales +local capteurGlobal = uservariables['Capteur électricité'] +local capteurCptHP = uservariables['ConsoCapteurHP'] +local capteurCptHC = uservariables['ConsoCapteurHC'] +local idxCptHP = uservariables['IdxCptHP'] +local idxCptHC = uservariables['IdxCptHC'] +local flagHC = uservariables['FlagHC'] +local flagHP = uservariables['FlagHP'] +local lastValueCptElecGlobal = uservariables['LastValueCptElecGlobal'] + +-- Mode debug Oui / Non +local debug = uservariables['debug'] + +-- Fonction de mise à jour +function update(device, id, power, energy, index) + commandArray[index] = {['UpdateDevice'] = id .. "|0|" .. power .. ";" .. energy} + return +end + +commandArray = {} + +-- On prend en compte a chaque changement de valeur du compteur global +if (devicechanged[capteurGlobal]) then + if (debug == 'OUI') then + print('-- Calcul Compteurs HC / HP --') + print('CapteurGlobal = '..capteurGlobal) + print('CapteurCptHP = '..capteurCptHP) + print('CapteurCptHC = '..capteurCptHC) + print('idxCptHP = '..tostring(idxCptHP)) + print('idxCptHC = '..tostring(idxCptHC)) + print('flagHP = '..tostring(flagHP)) + print('flagHC = '..tostring(flagHC)) + print('LastValueCptElecGlobal = '..tostring(lastValueCptElecGlobal)) + end + + -- Recuperation des valeurs du compteur global + local consoCumule + local consoInstant + consoInstant, consoCumule = otherdevices_svalues[capteurGlobal]:match("([^;]+);([^;]+)") + consoInstant = tonumber(consoInstant) + consoCumule = tonumber(consoCumule) + + if (debug == 'OUI') then + print('Conso Instant = '..tostring(consoInstant)..' / Conso Cumule = '..tostring(consoCumule)..' ') + end + + -- Calcul de l'ecart avec le dernier envoi de donnees + lastValueCptElecGlobal = tonumber(lastValueCptElecGlobal) + local consoDelta = consoCumule - lastValueCptElecGlobal + + if (debug == 'OUI') then + print('Delta conso = '..tostring(consoDelta)) + end + + local consoCumuleCible + local consoInstantCible + + if (otherdevices[flagHC] == 'On') then + -- Periode heures creuse + -- Recuperation des valeurs du compteur global + consoInstantCible, consoCumuleCible = otherdevices_svalues[capteurCptHC]:match("([^;]+);([^;]+)") + -- Seul le cumule du compteur nous interesse pour calculer la nouvelle valeur + consoCumuleCible = tonumber(consoCumuleCible) + + if (debug == 'OUI') then + print('Compteur cible = HC') + print('Valeur precedente = '..tostring(consoCumuleCible)) + print('Valeur ajustee = '..tostring(consoCumuleCible + consoDelta)) + end + + consoCumuleCible = consoCumuleCible + consoDelta + -- Mise à jour du compteur + update(capteurCptHC, idxCptHC, consoInstant, consoCumuleCible, 1) + + -- Mise à 0 de la conso intantanee du compteur HP + consoInstantHP, consoCumuleHP = otherdevices_svalues[capteurCptHP]:match("([^;]+);([^;]+)") + consoInstantHP = 0 + update(capteurCptHP, idxCptHP, consoInstantHP, consoCumuleHP, 2) + else + -- Periode heures pleines + -- Recuperation des valeurs du compteur global + consoInstantCible, consoCumuleCible = otherdevices_svalues[capteurCptHP]:match("([^;]+);([^;]+)") + -- Seul le cumule du compteur nous interesse pour calculer la nouvelle valeur + consoCumuleCible = tonumber(consoCumuleCible) + + if (debug == 'OUI') then + print('Compteur cible = HP') + print('Valeur precedente = '..tostring(consoCumuleCible)) + print('Valeur ajustee = '..tostring(consoCumuleCible + consoDelta)) + end + + consoCumuleCible = consoCumuleCible + consoDelta + -- Mise à jour du compteur + update(capteurCptHP, idxCptHP, consoInstant, consoCumuleCible, 3) + + -- Mise à 0 de la conso intantanee du compteur HC + consoInstantHC, consoCumuleHC = otherdevices_svalues[capteurCptHC]:match("([^;]+);([^;]+)") + consoInstantHC = 0 + update(capteurCptHC, idxCptHC, consoInstantHC, consoCumuleHC, 4) + end + + -- Sauvegarde de la valeur du compteur global pour prochain calcul + commandArray['Variable:LastValueCptElecGlobal'] = tostring(consoCumule) + + if (debug == 'OUI') then + print('-- Fin Calcul Compteur HC / HP --') + end +end + +return commandArray diff --git a/lua/script_device_demo.lua b/lua/script_device_demo.lua new file mode 100644 index 0000000..98e706c --- /dev/null +++ b/lua/script_device_demo.lua @@ -0,0 +1,39 @@ +-- demo device script +-- script names have three name components: script_trigger_name.lua +-- trigger can be 'time' or 'device', name can be any string +-- domoticz will execute all time and device triggers when the relevant trigger occurs +-- +-- copy this script and change the "name" part, all scripts named "demo" are ignored. +-- +-- Make sure the encoding is UTF8 of the file +-- +-- ingests tables: devicechanged, otherdevices,otherdevices_svalues +-- +-- device changed contains state and svalues for the device that changed. +-- devicechanged['yourdevicename']=state +-- devicechanged['svalues']=svalues string +-- +-- otherdevices and otherdevices_svalues are arrays for all devices: +-- otherdevices['yourotherdevicename']="On" +-- otherdevices_svalues['yourotherthermometer'] = string of svalues +-- +-- Based on your logic, fill the commandArray with device commands. Device name is case sensitive. +-- +-- Always, and I repeat ALWAYS start by checking for the state of the changed device. +-- If you would only specify commandArray['AnotherDevice']='On', every device trigger will switch AnotherDevice on, which will trigger a device event, which will switch AnotherDevice on, etc. +-- +-- The print command will output lua print statements to the domoticz log for debugging. +-- List all otherdevices states for debugging: +-- for i, v in pairs(otherdevices) do print(i, v) end +-- List all otherdevices svalues for debugging: +-- for i, v in pairs(otherdevices_svalues) do print(i, v) end +-- +-- TBD: nice time example, for instance get temp from svalue string, if time is past 22.00 and before 00:00 and temp is bloody hot turn on fan. + +print('this will end up in the domoticz log') + +commandArray = {} +if (devicechanged['MyDeviceName'] == 'On' and otherdevices['MyOtherDeviceName'] == 'Off') then + commandArray['MyOtherDeviceName']='On' +end +return commandArray diff --git a/lua/script_time_ESP8266.lua b/lua/script_time_ESP8266.lua new file mode 100755 index 0000000..84f63a0 --- /dev/null +++ b/lua/script_time_ESP8266.lua @@ -0,0 +1,49 @@ +-- demo device script +-- script names have three name components: script_trigger_name.lua +-- trigger can be 'time' or 'device', name can be any string +-- domoticz will execute all time and device triggers when the relevant trigger occurs +-- +-- copy this script and change the "name" part, all scripts named "demo" are ignored. +-- +-- Make sure the encoding is UTF8 of the file +-- +-- ingests tables: devicechanged, otherdevices,otherdevices_svalues +-- +-- device changed contains state and svalues for the device that changed. +-- devicechanged['yourdevicename']=state +-- devicechanged['svalues']=svalues string +-- +-- otherdevices and otherdevices_svalues are arrays for all devices: +-- otherdevices['yourotherdevicename']="On" +-- otherdevices_svalues['yourotherthermometer'] = string of svalues +-- +-- Based on your logic, fill the commandArray with device commands. Device name is case sensitive. +-- +-- Always, and I repeat ALWAYS start by checking for the state of the changed device. +-- If you would only specify commandArray['AnotherDevice']='On', every device trigger will switch AnotherDevice on, which will trigger a device event, which will switch AnotherDevice on, etc. +-- +-- The print command will output lua print statements to the domoticz log for debugging. +-- List all otherdevices states for debugging: +-- for i, v in pairs(otherdevices) do print(i, v) end +-- List all otherdevices svalues for debugging: +-- for i, v in pairs(otherdevices_svalues) do print(i, v) end +-- +-- TBD: nice time example, for instance get temp from svalue string, if time is past 22.00 and before 00:00 and temp is bloody hot turn on fan. + +--recupere les minutes +time=os.time() +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) + +commandArray = {} +--if (minutes == 0 or minutes == 30) then +if (minutes%5 == 0) then + if otherdevices['ESP8266_31_2'] == 'On' then + -- commandArray['ESP8266_31_2']='Off' + else + -- commandArray['ESP8266_31_2']='On' + end + +end +--end +return commandArray diff --git a/lua/script_time_Frigo.lua b/lua/script_time_Frigo.lua new file mode 100755 index 0000000..a774dcf --- /dev/null +++ b/lua/script_time_Frigo.lua @@ -0,0 +1,28 @@ +require "scripts/lua/functions" + +--recupere les minutes +time=os.time() +seconds=tonumber(os.date('%S',time)) +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) +jour=tonumber(os.date('%w',time)) +mois=tonumber(os.date('%M',time)) + + +--Initialise la commande de retour finale +commandArray={} + +-- ------------------------------------------------------------------------------ +-- Porte Frigo ouverte +-- ------------------------------------------------------------------------------ +debug('Porte Frigo ' .. otherdevices['Porte Frigo'] .. ' temps ' .. lastUpdateOfDevice('Porte Frigo')) +-- Pas de traitement en cas d'alerte fumée +if otherdevices['Porte Frigo'] ~= 'Closed' + -- Porte ouverte depuis trop longtemps + and (lastUpdateOfDevice('Porte Frigo')) > 300 then + +-- commandArray['SendNotification']='Frigo alerte#La porte du frigo est ouverte depuis trop longtemps !' + +end + +return commandArray diff --git a/lua/script_time_Garage.atester b/lua/script_time_Garage.atester new file mode 100644 index 0000000..02c272c --- /dev/null +++ b/lua/script_time_Garage.atester @@ -0,0 +1,21 @@ +-- script_time_garagedoor.lua +t1 = os.time() +s = otherdevices_lastupdate['Garagedeur'] +-- returns a date time like 2013-07-11 17:23:12 + +year = string.sub(s, 1, 4) +month = string.sub(s, 6, 7) +day = string.sub(s, 9, 10) +hour = string.sub(s, 12, 13) +minutes = string.sub(s, 15, 16) +seconds = string.sub(s, 18, 19) + +commandArray = {} + +t2 = os.time{year=year, month=month, day=day, hour=hour, min=minutes, sec=seconds} +difference = (os.difftime (t1, t2)) +if (otherdevices['Garagedeur'] == 'Open' and difference > 600 and difference < 700) then + commandArray['SendNotification']='Garage door alert#The garage door has been open for more than 10 minutes!' +end + +return commandArray diff --git a/lua/script_time_IP.lua b/lua/script_time_IP.lua new file mode 100755 index 0000000..5455d6d --- /dev/null +++ b/lua/script_time_IP.lua @@ -0,0 +1,52 @@ +--curl http://domogeek.entropialux.com/vigilance/56/ + +require "scripts/lua/functions" + +--recupere les minutes +time=os.time() +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) + +commandArray = {} + +-- Function to update a switch +function updateIP() + local idx = 1144 + local cmd = "curl -k -y 1 https://api4.my-ip.io/ip" + local vac = os.capture(cmd, true) + + print("IP actuelle"..vac) + local level = 0 + + local old_ip = otherdevices_svalues['Mon_IP'] + if old_ip ~= vac then + commandArray['SendNotification']='Changement IP '..vac..'#Attention changement IP '..vac..' #0' + + print("Recherche ip publique " .. cmd .. ": "..vac) + commandArray['UpdateDevice']=idx..'|'..level..'|'..vac + commandArray['SendEmail']='Changement IP#'..ip..'#souti@free.fr' + return vac + else + print("Pas de changement IP : "..vac..' '..old_ip) + commandArray['UpdateDevice']=idx..'|'..level..'|'..vac + return vac + end +end + + +time = os.date("*t") + +if heures%3 == 0 and minutes % 10 == 8 then + local old_ip = otherdevices_svalues['Mon_IP'] + local cmd = "curl -s -m 5 \"http://".. old_ip ..":81/name.txt\"" + print("Cmd="..cmd) + local ok = os.capture(cmd, true) + print("Ok="..ok .." IP="..old_ip) + if ok ~= "Akhenaton" then + print("updateIP") + ip = updateIP() + --commandArray['SendEmail']='Changement IP#'..ip..'#souti@free.fr' + end +end + +return commandArray diff --git a/lua/script_time_Lumieres.lua b/lua/script_time_Lumieres.lua new file mode 100755 index 0000000..c02d91a --- /dev/null +++ b/lua/script_time_Lumieres.lua @@ -0,0 +1,92 @@ +require "scripts/lua/functions" + +--recupere les minutes +time=os.time() +seconds=tonumber(os.date('%S',time)) +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) +jour=tonumber(os.date('%w',time)) +mois=tonumber(os.date('%M',time)) + + +--Initialise la commande de retour finale +commandArray={} + + +-- ----------------------------------------------------------------------- +-- Test le nombre d'erreur dans le log toutes les heures +-- ----------------------------------------------------------------------- +if (false and minutes == 0) then + local var = os.capture("grep Error /var/log/domoticz.log |wc -l") + --print(var) + + if (tonumber(var) > 0 and tonumber(uservariables['Variable:Erreurs']) == 0) then + commandArray['SendNotification']='Alerte Erreur '..var..'#Attention Il y a des erreurs dans domoticz #0' + + end + commandArray['Variable:Erreurs']=var +end + +-- ----------------------------------------------------------------------- +-- Vérifie le nombre de sequences capturées par motion +-- ----------------------------------------------------------------------- +if (minutes % 10 == 1) then + local f = io.popen("ls /media/WDBlue/motion/CAM21/*.avi |grep avi |uniq| wc -l") -- runs command + local l = f:read("*a") -- read output of command + debug("Nombre de detection "..l) + f:close() + commandArray['PhotoMotion']=tostring(l) + commandArray['UpdateDevice']="136|0|"..l +end + +-- ------------------------------------------------------------------------------ +-- Lampes eteinte après 22 heures 30 / 23 heures si pas d'activite depuis n minutes +-- ------------------------------------------------------------------------------ +-- Pas de traitement en cas d'alerte fumée +if (minutes%1==0) + and otherdevices['DétecteurFuméeCuisine'] == "Normal" + -- Pas de traitement si lampe allumée il y a moins d'une 1/2 heure + --and (lastUpdateOfDevice('Lampe_Buffet') > 1800) -- and otherdevices['Lampe_Buffet'] == 'On') + then + debug('Test extinction lumieres') + if ( + ( + (heures == 22 and minutes >= 0) or + (heures >= 23 and heures <= 5) or + (heures >= 09 and heures <= 10 ) or + (otherdevices['Presence'] == 'Off') + ) + ) then + + t1 = os.time() + s = uservariables_lastupdate['DerniereDetection'] --otherdevices_lastupdate['Detecteur Salon'] + -- returns a date time like 2013-07-11 17:23:12 + year = string.sub(s, 1, 4) + month = string.sub(s, 6, 7) + day = string.sub(s, 9, 10) + hour = string.sub(s, 12, 13) + minu = string.sub(s, 15, 16) + seconds = string.sub(s, 18, 19) + + t2 = os.time{year=year, month=month, day=day, hour=hour, min=minu, sec=seconds} + difference = (os.difftime (t1, t2)) + debug("Eteindre les lumieres, DerniereDetection="..tostring(difference)..' heures='..tostring(heures)) + if (difference > 300 and ( + (heures >= 22 and (minutes >= 0)) + or (heures >= 23) + or (heures <= 5) + ) + ) + then + debug("Extinction des lumieres") + switchIfNeeded('Lampe_Halogene', 'Off') + sleep(1) + switchIfNeeded('Lampe_Buffet', 'Off') + sleep(1) + switchIfNeeded('Lampe_Tele', 'Off') + --switchIfNeeded('SonoJasper', 'Off') + end + end +end + +return commandArray diff --git a/lua/script_time_Presence_new.lua b/lua/script_time_Presence_new.lua new file mode 100755 index 0000000..2bd09c1 --- /dev/null +++ b/lua/script_time_Presence_new.lua @@ -0,0 +1,80 @@ +require "scripts/lua/functions" + +--recupere les minutes +time=os.time() +seconds=tonumber(os.date('%S',time)) +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) +jour=tonumber(os.date('%w',time)) +mois=tonumber(os.date('%M',time)) + + +--Initialise la commande de retour finale +commandArray={} + +-- ----------------------------------------------------------------------- +--recupere les minutes +-- ----------------------------------------------------------------------- +if (true or minutes % 10 == 5) then + debug('####### Lancement du check Presence ' ..heures..'h'..minutes) + if (otherdevices['Vacances'] == 'On') then + switchIfNeeded('Presence','Off') + else + if otherdevices['Domi'] == 'On' + or otherdevices['Moi'] == 'On' + or otherdevices['Theo'] == 'On' + or otherdevices['Manon'] == 'On' + then + debug(' Presence détectée par téléphone à la maison') + switchIfNeeded('Presence','On') + elseif (true) then + switchIfNeeded('Presence','Off') + elseif ( + (josdJourChome() or otherdevices['PresenceForcee'] == 'On') + and otherdevices['AbsenceFamille'] == 'Off') + then + debug(' Jour Chômé / Presence normale à la maison') + switchIfNeeded('Presence','On') + else + local jourS=josdGetJourSemaine() + debug("jour "..jourS) + if otherdevices['AbsenceFamille'] == 'Off' then + if ( + --(jourS == "mercredi" and (heures >= 13 or (heures == 12 and minutes >= 30))) + (heures >= 18 or (heures == 17 and minutes >= 30)) + or (heures < 8 or (heures == 8 and minutes <= 10)) + or otherdevices["Zone B"] == 'On' + ) then + debug(' Jour non Chômé pas de vacances '..tostring(heures)) + switchIfNeeded('Presence','On') + else + switchIfNeeded('Presence','Off') + end + else + if ( + ( + (heures == 8 and minutes <= 15) or heures < 8) + or heures >= 20 + or otherdevices['Moi'] == 'On' + -- or otherdevices['Akhenaton'] == 'On' + or otherdevices['Philae'] == 'On' + ) then + switchIfNeeded('Presence','On') + else + switchIfNeeded('Presence','Off') + end + end + end + end +end + + +-- http://cellier.home:8081/0/detection/start + +-- http://192.168.1.3:8080/0/detection/pause + +-- http://cellier.home:8081/0/detection/start + +-- http://192.168.1.3:8080/0/detection/start + +return commandArray diff --git a/lua/script_time_Solaire.lua b/lua/script_time_Solaire.lua new file mode 100755 index 0000000..24b999a --- /dev/null +++ b/lua/script_time_Solaire.lua @@ -0,0 +1,38 @@ +require "scripts/lua/functions" + +--recupere les minutes +time=os.time() +seconds=tonumber(os.date('%S',time)) +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) +jour=tonumber(os.date('%w',time)) +mois=tonumber(os.date('%M',time)) + + +--Initialise la commande de retour finale +commandArray={} + +-- ------------------------------------------------------------------------------ +-- Gestion de la production solaire +-- ------------------------------------------------------------------------------ +--if (minutes %1 == 0) then + local tab1 = split(otherdevices['CONSOMMATION_GENERALE'], ";") + local watt_consomme = tonumber(tab1[1]) + --print("Time Consommation générale "..watt_consomme) + + local tab = getValuesInTab('SolaireProduction') + print("Time Production Solaire "..tab[1]) + local watt_solaire = tonumber(tab[1]) + + + if watt_solaire ~= nil and watt_solaire > 100 then + if watt_consomme < 80 then + print("Consommation devient faible => routage solaire") + else + print("Consommation encore importante solaire 100% injecté") + end + end + +--end + +return commandArray diff --git a/lua/script_time_Sunset.lua b/lua/script_time_Sunset.lua new file mode 100755 index 0000000..f6a9ca8 --- /dev/null +++ b/lua/script_time_Sunset.lua @@ -0,0 +1,35 @@ +-- School Holiday Status Request from Domogeek API +-- http://api.domogeek.fr/static/doc/index.html#api-Domogeek-GetSchoolHoliday +-- Prerequis: 3 switch On/Off: "Zone A", "Zone B", "Zone C" + +--curl http://domogeek.entropialux.com/sun/brest/all/now +--{"dayduration": "9:51", "sunset": "18:28", "zenith": "13:32", "sunrise": "8:37"} + +require "scripts/lua/functions" + +--recupere les minutes +time=os.time() +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) + +commandArray = {} +time = os.date("*t") + +-- Trigger at 0:03 every day +if (time.min == 3 and (time.hour == 0 or time.hour == 8)) then + + -- retourne l'heure du lever de soleil ex: "06:41" + leverSoleil = string.sub(os.date("!%X",60*timeofday['SunriseInMinutes']), 1, 5) + + -- retourne l'heure du coucher de soleil ex: "22:15" + coucherSoleil = string.sub(os.date("!%X",60*timeofday['SunsetInMinutes']), 1, 5) + + print("Lever/Coucher "..leverSoleil..'-'..coucherSoleil) + + commandArray['Variable:Couche']=coucherSoleil + commandArray['Variable:Lever']=leverSoleil + + --updateSunset("redon") +end + +return commandArray diff --git a/lua/script_time_Vacances.lua b/lua/script_time_Vacances.lua new file mode 100755 index 0000000..f27dee5 --- /dev/null +++ b/lua/script_time_Vacances.lua @@ -0,0 +1,68 @@ +require "scripts/lua/functions" + +commandArray = {} + + +-- School Holiday Status Request from Domogeek API +-- http://api.domogeek.fr/static/doc/index.html#api-Domogeek-GetSchoolHoliday +-- Prerequis: 3 switch On/Off: "Zone A", "Zone B", "Zone C" + +--recupere les minutes +time=os.time() +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) + +-- Path to curl +-- Windows: curl = 'C:\\bin\\curl.exe' +curl = "curl" + +-- Devices (Switch On/Off on virtual hardware) +--switchA = "Zone A" +switchB = "Zone B" +--switchC = "Zone C" + +-- Function to get result of HTTP request +function os.capture(cmd, raw) + local f = assert(io.popen(cmd, 'r')) + local s = assert(f:read('*a')) + f:close() + if raw then return s end + s = string.gsub(s, '^%s+', '') + s = string.gsub(s, '%s+$', '') + s = string.gsub(s, '[\n\r]+', ' ') + return s +end + +-- Function to update a switch +function updateZoneSwitch(zone, switch) + local cmd = curl .. " -y 2 http://domogeek.entropialux.com/schoolholiday/" .. zone .. "/now" + local vac = os.capture(cmd, true) + print("School Holiday Status: " .. cmd .. ": " .. tostring(vac)) + + if (vac == "False") then + --if (otherdevices[switch] == "On") then + --commandArray[switch] = "Off"; + --end + else + if (vac ~= "") then + --commandArray[switch] = "On"; + end + end +end + + + +-- Trigger at 0:02 every day +if ((minutes == 5 and heures == 2)) then + + -- Zone A + -- updateZoneSwitch("A", switchA) + + -- Zone B + updateZoneSwitch("B", "Zone B") + + -- Zone C + -- updateZoneSwitch("C", switchC) +end + +return commandArray diff --git a/lua/script_time_angle.lua b/lua/script_time_angle.lua new file mode 100644 index 0000000..6b8a5c1 --- /dev/null +++ b/lua/script_time_angle.lua @@ -0,0 +1,120 @@ +require "scripts/lua/functions" + +-- URL du fichier JSON +local weather_url = "http://api.openweathermap.org/data/2.5/weather?q=La%20gacilly,fr&APPID=feba3f4d926db3b358a25ec782bd1c8b&lang=FR&units=metric" +local forecast_url = "http://api.openweathermap.org/data/2.5/forecast?q=La%20gacilly,fr&APPID=feba3f4d926db3b358a25ec782bd1c8b&lang=FR&units=metric" + +time=os.time() +seconds=tonumber(os.date('%S',time)) +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) +jour=tonumber(os.date('%w',time)) +mois=tonumber(os.date('%M',time)) + +local function forecast(pressure) + -- pressureForecast = tonumber(forecast) + + if (pressure == 0) then + pressureForecast = 0 + elseif (pressure > 1030) then + pressureForecast = 1 + elseif ((pressure > 1010) and (pressure <= 1030)) then + pressureForecast = 2 + elseif ((pressure > 990) and (pressure <= 1010)) then + pressureForecast = 3 + elseif ((pressure > 970) and (pressure <= 990)) then + pressureForecast = 4 + end + return pressureForecast +end + +local function updateBarometerDevice(deviceId, temperature, humidity, pressure, cloud) + local svalue = string.format("%.1f;%d;%d;%d;%d;", temperature, humidity, humidity, pressure, cloud) + local url = domoticzURL..'/json.htm?type=command¶m=udevice&idx='..deviceId..'&svalue='..svalue + print(url) + result = os.execute(curl..'"'..url..'" &') + print(result) +end + +commandArray = {} + +if minutes == 0 and heures == 8 then + if mois == 2 and jour == 1 then + sendNotification('Changement d\'angle#Passer l\'angle des panneaux à 60°!') + end + if mois == 3 and jour == 1 then + sendNotification('Changement d\'angle#Passer l\'angle des panneaux à 45°!') + end + if mois == 4 and jour == 24 then + sendNotification('Changement d\'angle#Passer l\'angle des panneaux à 30°!') + end + if mois == 8 and jour == 19 then + sendNotification('Changement d\'angle#Passer l\'angle des panneaux à 45°!') + end + if mois == 10 and jour == 13 then + sendNotification('Changement d\'angle#Passer l\'angle des panneaux à 60°!') + end +end + +if minutes % 10 == 0 then + local jsonContent = getJSONContent(weather_url) + + local devices = decodeJSON(jsonContent) + printTableAsTree(devices) + + local nuage = 0 + local pluie_1h = 0 + local main = searchKeyInTable("main", devices['weather']) + print('main='..main) + local nuage = searchKeyInTable("all", devices['clouds']) + + print("pluie " .. pluie_1h) + print("Nuage " .. nuage) + + updateDeviceValue(1159, ';'..pluie_1h) + updateDeviceValue(1160, nuage) + + local temp_min = searchKeyInTable("temp", devices) + local humidity = searchKeyInTable("humidity", devices) + local pressure = searchKeyInTable("pressure", devices) + local cloud = searchKeyInTable("all", devices) + local forecast = forecast(pressure) + + updateBarometerDevice(1157, temp_min, humidity, pressure, forecast) + + local temp = searchKeyInTable("temp", devices) + local feels_like = searchKeyInTable("feels_like", devices) + local deg = searchKeyInTable("deg", devices) + local speed = searchKeyInTable("speed", devices) * 10 + local gust = searchKeyInTable("gust", devices) * 10 + local angle = searchKeyInTable("deg", devices['wind']) + local compass = convertirAngle(angle) + +-- print("deg"..tostring(deg)) + updateDeviceValue(1158, string.format("%d;%s;%.1f;%.1f;%.1f;%.1f", deg, compass, speed, gust, temp, feels_like)) +end + +if heures % 3 == 0 and minutes == 26 then + local jsonContent = getJSONContent(forecast_url) + --print(jsonContent) + local data = decodeJSON(jsonContent) + + -- Extraire les 6 premières valeurs du champ "all" + local cloud_values = {} + for i = 1, math.min(6, #data.list) do + table.insert(cloud_values, data.list[i].clouds.all) + end + + -- Afficher les valeurs extraites + local somme = 0 + for i, value in ipairs(cloud_values) do + print("Cloud coverage for point " .. i .. ": " .. value) + somme = somme + tonumber(value) + end + local moyenne = somme / 6 + print("Cloud coverage average".. tostring(moyenne)) + updateDeviceValue(1199, tostring(moyenne)) + +end + +return commandArray diff --git a/lua/script_time_cam.lua b/lua/script_time_cam.lua new file mode 100644 index 0000000..77cae60 --- /dev/null +++ b/lua/script_time_cam.lua @@ -0,0 +1,40 @@ +-- demo time script +-- script names have three name components: script_trigger_name.lua +-- trigger can be 'time' or 'device', name can be any string +-- domoticz will execute all time and device triggers when the relevant trigger occurs +-- +-- copy this script and change the "name" part, all scripts named "demo" are ignored. +-- +-- Make sure the encoding is UTF8 of the file +-- +-- ingests tables: otherdevices,otherdevices_svalues +-- +-- otherdevices and otherdevices_svalues are two item array for all devices: +-- otherdevices['yourotherdevicename']="On" +-- otherdevices_svalues['yourotherthermometer'] = string of svalues +-- +-- Based on your logic, fill the commandArray with device commands. Device name is case sensitive. +-- +-- Always, and I repeat ALWAYS start by checking for a state. +-- If you would only specify commandArray['AnotherDevice']='On', every time trigger (e.g. every minute) will switch AnotherDevice on. +-- +-- The print command will output lua print statements to the domoticz log for debugging. +-- List all otherdevices states for debugging: +-- for i, v in pairs(otherdevices) do print(i, v) end +-- List all otherdevices svalues for debugging: +-- for i, v in pairs(otherdevices_svalues) do print(i, v) end + +time=os.time() +seconds=tonumber(os.date('%S',time)) +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) +jour=tonumber(os.date('%w',time)) +mois=tonumber(os.date('%M',time)) + +commandArray = {} + +if heures ==23 and minute == 00 then + +end + +return commandArray \ No newline at end of file diff --git a/lua/script_time_consigne.lua b/lua/script_time_consigne.lua new file mode 100755 index 0000000..af4d775 --- /dev/null +++ b/lua/script_time_consigne.lua @@ -0,0 +1,345 @@ +require "scripts/lua/functions" + +--recupere les minutes +time=os.time() +seconds=tonumber(os.date('%S',time)) +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) +jour=tonumber(os.date('%w',time)) +mois=tonumber(os.date('%M',time)) + + +--Initialise la commande de retour finale +commandArray={} + +-- --------------------------------- +-- Réglage des consigne temperature +-- --------------------------------- + +function callDomoticz(device, svalue) + local idx = otherdevices_idx[device] + if (svalue == nil) then + print("CONSIGNE Call Domoticz Update canceled null value"..tostring(idx).." "..svalue) + end + print("CONSIGNE Call Domoticz IDx="..idx.." device="..device.." value="..tostring(svalue)) + + --commandArray['SetSetpoint:'..idx]=svalue + + --local cmd ='curl -y 1 "http://localhost:81/json.htm?type=command¶m=udevice&idx='..idx..'&nvalue=0&svalue='..svalue..'"' + + --local vac = os.capture(cmd, true) + --os.execute(cmd) + --debug("Domoticz called pour consige " .. cmd .. ": ") -- .. vac) + print("CONSIGNE Consigne "..otherdevices_svalues[device].." svalue="..svalue.." idx="..tostring(idx).." "..device) + if tonumber(otherdevices_svalues[device]) ~= tonumber(svalue) then + update(idx,tonumber(svalue),tonumber(svalue)) + print("CONSIGNE Update "..tostring(idx).." "..svalue) + else + print("CONSIGNE Update inutile "..tostring(idx).." "..svalue) + end + --sleep(1) +end + +--print("CONSIGNE ++++++++++++PRESENCE MANON "..otherdevices['Manon']) + +if minutes%1 == 0 + --and otherdevices['ChauffageGeneral'] == 'Off' +then + + print('CONSIGNE ####### Lancement du calcul consigne ' ..heures..'h'..minutes) + + local temp_ext = getExternalTempRef("BarometreLaGacilly") + + local heureCreuse = (uservariables['HeuresCreuses'] == 'On') + local delta = -0.5 + if (heureCreuse) then + delta = 0.5 + end + -- Pas d'heure creuse + delta = 0 + + local jourS=josdGetJourSemaine() + local consigneConfortGrenier = 18 + local consigneAbsence = otherdevices['ConsigneAbsence'] + delta + local consigneConfort = otherdevices['ConsigneChauffageGeneral'] + delta + local consigneConfortSalon = uservariables['ConfortSalon'] + delta + local consigneConfortCuisine = uservariables['ConfortCuisine'] + delta + local consigneConfortBureau = uservariables["ConfortBureau"] + delta + local consigneConfortManon = uservariables["ConfortManon"] + delta + local consigneConfortTheo = uservariables["ConfortTheo"] + delta + local consigneConfortChambre = uservariables["ConfortChambre"] + delta + --local consigneConfortSalon = 17.5 + delta + local consigneHorsGel = 14 + + -- Cheminee allumée + local currentTempCheminee = tonumber(otherdevices_svalues["Cheminee"]) + local variation = variationTemp2("Cheminee", 120) -- variation des 120 dernières minutes + + local coucheManon = 17 + local coucheTheo = 17 + local reveilManon = uservariables["HeureLeveManon"] + local reveilTheo = uservariables["HeureLeveTheo"] + local reveilManonEcole = uservariables["HeureLeveEcoleManon"] + local reveilTheoEcole = uservariables["HeureLeveEcoleTheo"] + local presenceManon = ( + otherdevices['Manon'] == "On" or uservariables['Detection_Manon_20H'] == 1 + or otherdevices["Zone B"] == 'On' + or (((jourS == "vendredi" and heures >= 18) or jourS == "samedi" or + (jourS == "dimanche" and heures <= 18) + ) + -- or otherdevices["Manon"] == 'On' + -- ) + -- and uservariables['Detection_Manon_20H'] == "1" + ) + ) + and otherdevices['AbsenceFamille'] == 'Off' + local presenceTheo = ( + otherdevices['Theo'] == "On" or uservariables['Detection_Theo_20H'] == 1 + or otherdevices["Zone B"] == 'On' + or ( + --(jourS == "jeudi" and heures >= 18) or + (jourS == "vendredi" and heures >= 18) or + jourS == "samedi" or + (jourS == "dimanche" and uservariables['Detection_Theo_20H'] == 1) ) + --and uservariables['Detection_Theo_20H'] == "1") + -- or otherdevices["Theo"] == 'On' + -- ) + -- ) + ) + and otherdevices['AbsenceFamille'] == 'Off' + local presenceMoi = (otherdevices['Moi'] == "On" ) + or ( + (jourS == "lundi" or jourS == "mardi" or jourS == "mercredi" or jourS == "jeudi" or jourS == "vendredi") and (heures >= 8 and heures <= 18) and otherdevices['jerome'] == "On" + ) + local presenceDomi = (otherdevices['Domi'] == "On" or jourS == "samedi" or jourS == "dimanche") + and otherdevices['AbsenceFamille'] == 'Off' + local yaPersonne = not (presenceManon or presenceTheo or presenceMoi or presenceDomi or otherdevices['PresenceForcee'] == 'On') + if not yaPersonne then + if (heures >= 7 and heures <= 9) or (heures >= 11 and heures <= 14) or (heures >= 19 and heures <= 21) then + consigneConfortCuisine = uservariables['ConfortCuisine'] + delta + else + consigneConfortCuisine = uservariables['ConfortCuisine'] - 1 + end + end + print("CONSIGNE Cheminee variation"..tostring(variation)) + local cheminee_allumee = false + if (currentTempCheminee > 21.5 or (variation > 0 and currentTempCheminee >= 20)) then + cheminee_allumee = true; + print('CONSIGNE Cheminee fonctionne : arrêt radiateurs') + if (heures > 11) then + consigneConfortSalon = consigneHorsGel + end + + if (heures > 11 and heures < 20) then + consigneConfortManon = consigneAbsence + consigneConfortTheo = consigneAbsence + consigneConfortChambre = consigneAbsence + end + if ((not presenceMoi or otherdevices['jerome'] == 'Off') and otherdevices['Akhesa'] == 'Off') then + consigneConfortBureau = consigneHorsGel + end + end + --if ((not presenceMoi or otherdevices['jerome'] == 'Off' or josdJourChome())) then + -- consigneConfortBureau = consigneHorsGel + --end + + print("CONSIGNE Presence Manon "..tostring(presenceManon)); + print("CONSIGNE Presence Theo "..tostring(presenceTheo)); + print("CONSIGNE Presence moi "..tostring(presenceMoi)); + if (otherdevices['Manon'] == 'On' and heures >= 17) then + coucheManon = heures + end + + if (otherdevices['Vacances'] == 'On') then + print("CONSIGNE Vacances"); + + callDomoticz('ConsigneConfortCuisine',consigneHorsGel) -- Chambre + callDomoticz('ConsigneConfortChambre',consigneHorsGel) -- Chambre + callDomoticz('ConsigneConfortTheo',consigneHorsGel) -- ChconsigneConfortambreTheo + callDomoticz('ConsigneConfortManon', consigneHorsGel) -- ChambreManon + callDomoticz('ConsigneConfortBureau',consigneHorsGel) -- Bureau + callDomoticz('ConsigneConfortSalon',consigneHorsGel) -- Salon + callDomoticz('ConsigneConfortGrenier',consigneHorsGel) -- Salon + + else + + if otherdevices['Force_Grenier'] == "On" then + callDomoticz('ConsigneConfortGrenier',consigneConfortGrenier) + elseif heures > 18 or heures < 8 or josdJourChome() or otherdevices['Domi_Work'] == "Off" then + callDomoticz('ConsigneConfortGrenier', 6) --consigneHorsGel) + elseif otherdevices['Domi_Work'] == "On" then + callDomoticz('ConsigneConfortGrenier',consigneConfortGrenier) + end + --commandArray['Presence']='Off + -- Presence à la maison + ------------------------------------------------------------------------ + if (josdJourChome() or otherdevices['PresenceForcee'] == 'On') then + print('CONSIGNE Jour Chômé / consigne temperature présence') + -- callDomoticz('ConsigneConfortBureau',consigneConfortBureau) -- Bureau + if (heures >= 21 or heures < 11 or yaPersonne) then + callDomoticz('ConsigneConfortCuisine',consigneAbsence) -- Salon + else + callDomoticz('ConsigneConfortCuisine',consigneConfortCuisine) -- Salon + end + if (heures >= 22 or heures < 8 or yaPersonne --or temp_ext < 3 + or cheminee_allumee) + then + callDomoticz('ConsigneConfortSalon',consigneAbsence) -- Salon + else + callDomoticz('ConsigneConfortSalon',consigneConfortSalon) -- Salon + end + if (heures >= 20 or heures < 8) then + callDomoticz('ConsigneConfortChambre',consigneConfortChambre) -- Chambre + else + callDomoticz('ConsigneConfortChambre',consigneAbsence) -- Chambre + end + if ( + (otherdevices['Akhesa'] == 'On' or otherdevices['jerome'] == 'On') + and (heures > 7 and heures < 21) + + ) then + callDomoticz('ConsigneConfortBureau',consigneConfortBureau) -- Bureau + else + callDomoticz('ConsigneConfortBureau',consigneHorsGel) -- Bureau + end + -- Heure Manon en vacances + if --(heures >= coucheManon or heures <= reveilManon) and + presenceManon then + callDomoticz('ConsigneConfortManon', consigneConfortManon) -- ChambreManon + else + callDomoticz('ConsigneConfortManon', consigneAbsence) -- ChambreManon + end + -- Heure Théo en vacances + if (heures >= coucheTheo or heures <= reveilTheo) and presenceTheo then + callDomoticz('ConsigneConfortTheo',consigneConfortTheo) -- ChambreTheo + else + callDomoticz('ConsigneConfortTheo',consigneAbsence) -- ChambreTheo + end + else + -- + if otherdevices['AbsenceFamille'] == 'Off' then + if otherdevices["Zone B"] == 'On' or otherdevices["PresenceForcee"] == 'On' then + print('CONSIGNE Jour vacances zone B ') + if (heures >= 17 or heures <= 8) then + callDomoticz('ConsigneConfortChambre',consigneConfortChambre) -- Chambre + else + callDomoticz('ConsigneConfortChambre',consigneAbsence) -- Chambre + end + + if (heures >= 21 or heures < 11 or (yaPersonne and heures < 16)) then + callDomoticz('ConsigneConfortCuisine',consigneAbsence) -- Salon + else + callDomoticz('ConsigneConfortCuisine',consigneConfortCuisine) -- Salon + end + + if (heures >= 22 or heures < 16 or (yaPersonne and heures < 16)) then + callDomoticz('ConsigneConfortSalon',consigneAbsence) -- Salon + else + callDomoticz('ConsigneConfortSalon',consigneConfortSalon) -- Salon + end + if ( + --heures >= 20 or heures < 9 or*/ + (otherdevices['Akhesa'] == 'Off' and otherdevices['jerome'] == 'Off') + or (heures > 21 and heures < 7) + ) then + callDomoticz('ConsigneConfortBureau',consigneHorsGel) -- Bureau + else + callDomoticz('ConsigneConfortBureau',consigneConfortBureau) -- Bureau + end + -- Heure Manon en vacances + if (heures >= coucheManon or heures <= reveilManon) and presenceManon then + callDomoticz('ConsigneConfortManon', consigneConfortManon) -- ChambreManon + else + callDomoticz('ConsigneConfortManon', consigneAbsence) -- ChambreManon + end + -- Heure Théo en vacances + if (heures >= coucheTheo or heures <= reveilTheo) and presenceTheo then + callDomoticz('ConsigneConfortTheo',consigneConfortTheo) -- ChambreTheo + else + callDomoticz('ConsigneConfortTheo',consigneAbsence) -- ChambreTheo + end + -- Heures hors vacances + -- Ecole + else --if (heures >= 17 or heures < 8) then + print('CONSIGNE Jour non Chômé pas de vacances '..tostring(heures).."h"..tostring(minutes)) + if (heures >= 20 or heures <= 6) then + callDomoticz('ConsigneConfortChambre',consigneConfortChambre) -- Chambre + else + callDomoticz('ConsigneConfortChambre',consigneAbsence) -- Chambre + end + + if (heures >= 21 or heures < 18 or (yaPersonne and heures < 18) --or temp_ext < 3 + ) then + callDomoticz('ConsigneConfortCuisine',consigneAbsence) -- Salon + else + callDomoticz('ConsigneConfortCuisine',consigneConfortCuisine) -- Salon + end + if (heures <= 16 or heures >= 22 or (yaPersonne and heures < 16) --or temp_ext < 3 + ) then + callDomoticz('ConsigneConfortSalon',consigneAbsence) -- Salon + else + callDomoticz('ConsigneConfortSalon',consigneConfortSalon) -- Salon + end + + if ( + (otherdevices['Akhesa'] == 'On' or otherdevices['jerome'] == 'On' or presenceMoi) + and (heures >= 7 and heures < 18) + ) then + callDomoticz('ConsigneConfortBureau',consigneConfortBureau) -- Bureau + else + callDomoticz('ConsigneConfortBureau',consigneHorsGel) -- Bureau + end + + -- Heure Manon école + if (presenceManon) then + callDomoticz('ConsigneConfortManon', consigneConfortManon) -- ChambreManon + else + callDomoticz('ConsigneConfortManon', consigneAbsence) -- ChambreManon + end + if (presenceTheo and (otherdevices['Akhesa'] == 'Off' or heures >= 21)) then + callDomoticz('ConsigneConfortTheo',consigneConfortTheo) -- ChambreTheo + else + callDomoticz('ConsigneConfortTheo',consigneAbsence) -- ChambreTheo + end + end + + else + callDomoticz('ConsigneConfortCuisine',consigneAbsence) + callDomoticz('ConsigneConfortTheo',consigneHorsGel) -- ChambreTheo + callDomoticz('ConsigneConfortManon', consigneHorsGel) -- ChambreManon + -- Absence famille + if ( + ((heures == 8 and minutes <= 15) or heures < 8) or heures >= 20) or + (otherdevices['Moi'] == 'On' + or otherdevices['Akhesa'] == 'On' or otherdevices['Presence'] == 'On' + or otherdevices['Nefertiti'] == 'On' or otherdevices['jerome'] == 'On' + ) + then + callDomoticz('ConsigneConfortChambre',consigneConfortChambre) -- Chambre + if (heures >= 22 or heures < 19) then + callDomoticz('ConsigneConfortSalon',consigneAbsence) -- Salon + else + callDomoticz('ConsigneConfortSalon',consigneConfortSalon) -- Salon + end + if (otherdevices['Akhesa'] == 'Off' and otherdevices['jerome'] == 'Off') + or ((heures > 21 and heures < 7) or cheminee_allumee) + then + callDomoticz('ConsigneConfortBureau',consigneHorsGel) -- Bureau + else + callDomoticz('ConsigneConfortBureau',consigneConfortBureau) -- Bureau + end + else + callDomoticz('ConsigneConfortChambre',consigneAbsence) -- Chambre + callDomoticz('ConsigneConfortBureau',consigneAbsence) -- Bureau + callDomoticz('ConsigneConfortSalon',consigneAbsence) -- Salon + callDomoticz('ConsigneConfortTheo',consigneAbsence) -- ChambreTheo + callDomoticz('ConsigneConfortManon', consigneAbsence) -- ChambreManon + callDomoticz('ConsigneConfortGrenier',consigneHorsGel) -- Salon + + end + end + end + end +end + +return commandArray diff --git a/lua/script_time_fumee.lua b/lua/script_time_fumee.lua new file mode 100755 index 0000000..713ed6b --- /dev/null +++ b/lua/script_time_fumee.lua @@ -0,0 +1,49 @@ +require "scripts/lua/functions" + +--recupere les minutes +time=os.time() +seconds=tonumber(os.date('%S',time)) +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) +jour=tonumber(os.date('%w',time)) +mois=tonumber(os.date('%M',time)) + + +--Initialise la commande de retour finale +commandArray={} + + +-- ------------------------------------------------------------------------------ +-- Lampes eteinte après 22 heures 30 / 23 heures si pas d'activite depuis 10 minutes +-- ------------------------------------------------------------------------------ +-- Pas de traitement en cas d'alerte fumée +if otherdevices['DétecteurFuméeCuisine'] == "Normal" + -- Pas de traitement si lampe allumée il y a moins d'une heure + and (lastUpdateOfDevice('Lampe_Buffet') > 3600 and otherdevices['Lampe_Buffet'] == 'On') + then + if ((heures >= 23 or (heures == 22 and minutes >= 30)) and (minutes%5==0)) then + + t1 = os.time() + s = uservariables_lastupdate['DerniereDetection'] --otherdevices_lastupdate['Detecteur Salon'] + -- returns a date time like 2013-07-11 17:23:12 + year = string.sub(s, 1, 4) + month = string.sub(s, 6, 7) + day = string.sub(s, 9, 10) + hour = string.sub(s, 12, 13) + minu = string.sub(s, 15, 16) + seconds = string.sub(s, 18, 19) + + t2 = os.time{year=year, month=month, day=day, hour=hour, min=minu, sec=seconds} + difference = (os.difftime (t1, t2)) + debug("Eteindre les lumieres, DerniereDetection="..tostring(difference)) + if (difference > 300 or heures >= 23) then + + switchIfNeeded('Lampe_Halogene', 'Off') + switchIfNeeded('Lampe_Buffet', 'Off') + switchIfNeeded('Lampe_Tele', 'Off') + switchIfNeeded('SonoJasper', 'Off') + end + end +end + +return commandArray diff --git a/lua/script_time_gcal.lua b/lua/script_time_gcal.lua new file mode 100755 index 0000000..465c388 --- /dev/null +++ b/lua/script_time_gcal.lua @@ -0,0 +1,137 @@ +--------------------------------- +-- Script de lecture de calendrier Google. +-- Actionne un interrupteur ou remplie un capteur virtuel Text +-- Auteur : Aurelien Neutrino +-- Date : 29 Novembre 2015 +-- Nécessite un capteur virtuel de type Text +-- Il faut suivre la source suivante et s'arrêter à la fin de l'étape 1 +-- source : +-- http://easydomoticz.com/agenda-google-et-domoticz-version-2-partie-1/ + +-- Pour récupérer le code permettant de se connecter +-- exécuter : sudo gcalcli --cal=Domoticz agenda '00:00' '23:59' --tsv --military +-- puis coller l'adresse dans un navigateur +-- +--------------------------------- +require "scripts/lua/functions" + +commandArray = {} +--Récupère l'heure et la date actuelle +time = os.time() +minutes=tonumber(os.date('%M',time)) +hours=tonumber(os.date('%H',time)) +jour = os.date('%d',time) +--Nombre de minutes depuis 00:00 +maintenant=tonumber(hours*60+minutes) + +--idx et nom du capteur Text +idxText = '203' +nomText="Agenda" + +--nom de l'agenda google +domoticz_cal="Domoticz" + +--fichier et chemin pour agenda +repertoire="/home/pi/" +file="googlecal.txt" + +-- Toutes les heures, on récupère l'agenda de la journée +if(maintenant%60==0)then + options="--tsv --military" + agenda_start="00:00" + agenda_end="23:59" + + -- Agenda Domoticz + lignecde="sudo gcalcli --cal="..domoticz_cal.." agenda ".."'"..agenda_start.."' '"..agenda_end.."' "..options + lignecde=lignecde.." > "..repertoire..file.." &" + os.execute(lignecde) + + + sleep(1) + -- Agenda Standard 4/ymDKXAZQtn9azD6vFmUPQ7fJ0jJFeJWOXu___bVKD68 + lignecde="sudo gcalcli --cal=jerome.delacotte@gmail.com agenda '"..agenda_start.."' '"..agenda_end.."' "..options + lignecde=lignecde.." >> "..repertoire..file.." &" + os.execute(lignecde) + + sleep(1) + -- Agenda Standard 4/ymDKXAZQtn9azD6vFmUPQ7fJ0jJFeJWOXu___bVKD68 + lignecde="sudo gcalcli --cal=jerome.delacotte@vif.fr agenda '"..agenda_start.."' '"..agenda_end.."' "..options + lignecde=lignecde.." >> "..repertoire..file.." &" + os.execute(lignecde) +--end + + local file = io.open(repertoire..file, "r") -- Ouvre le fichier en mode lecture + local ligne = {} -- Table pour les lignes du fichier + + if(file~=nil)then + --le fichier n'est pas vide + for line in file:lines() do -- Pour chaque lignes + table.insert(ligne, line) -- On insère les lignes dans la table + end + end + + for i, v in ipairs(ligne) do -- Lecture de la table des RDV + dateDebut,heureDebut,minutesDebut,dateFin,heureFin,minutesFin,action = v:match("([^;]+)\t([^;]+):([^;]+)\t([^;]+)\t([^;]+):([^;]+)\t([^;]+)") + action = action:gsub(" = ","=") + debutAction = heureDebut*60+minutesDebut + finAction = heureFin*60+minutesFin + anneeAction,moisAction,jourAction = dateDebut:match("([^;]+)-([^;]+)-([^;]+)") + if(action~=nil and action:find("=")~=nil and jourAction == jour)then + --L'action contient "=", c'est un interrupteur à actionner + debug("Action : "..action) + debug(maintenant.." : "..debutAction) + interrupteur,etat=action:match("([^;]+)=([^;]+)") + if(otherdevices[interrupteur]~=nil and(etat=='On' or etat=='Off' or etat=='ON' or etat=='OFF')and debutAction==maintenant)then + --L'interrupteur existe, l'état souhaité est reconnu + if(etat=='On'or etat=='Off')then + if(dateDebut~=dateFin)then + --l'action finit demain + finAction=finAction+(24*60) + end + debug(interrupteur.." passe à "..etat.." pendant "..tostring(finAction-maintenant).." minutes") + commandArray[interrupteur]=etat.." FOR "..tostring(finAction-maintenant) + if(otherdevices_svalues[nomText]=='')then + --Aucun pense-bête actuellement renseigné, on affiche l'action en cours. + --L'affichage d'un pense-bête est prioritaire sur l'affichage d'un changement d'état + debug("pense-bête : "..action) + commandArray['UpdateDevice']=idxText.."|0|"..action + end + elseif(etat=='ON')then + --ON (tout en majuscule) siginifie que l'action n'a pas de fin + debug(interrupteur.." passe à On") + commandArray[interrupteur]='On' + elseif(etat=='OFF')then + --OFF (tout en majuscule) siginifie que l'action n'a pas de fin + debug(interrupteur.." passe à Off") + commandArray[interrupteur]='Off' + else + --Etat non reconnu, on force l'interrupteur + debug(interrupteur.." passe à "..etat) + commandArray[interrupteur]=etat + end + elseif(otherdevices[interrupteur]==nil and debutAction==maintenant)then + --L'interrupteur n'existe pas, on affiche le pense-bête + commandArray['UpdateDevice']=idxText.."|0|"..action + elseif(finAction==maintenant and action == otherdevices_svalues[nomText])then + --L'action est terminée, on l'efface + commandArray['UpdateDevice']=idxText.."|0| " + end + elseif(action~=nil and action:find("Cong=")~=nil and jourAction == jour)then + commandArray['Presence']="on" + else + debug("###### Action : "..action) + if (debutAction==maintenant and jourAction == jour) then + --L'action ne correspond pas à un interrupteur à actionner, c'est donc un pense-bête, on l'affiche pendant la durée souhaitée + debug("####### Rappel agenda "..action) + commandArray['UpdateDevice']=idxText.."|0|"..action + else + if (finAction==maintenant and action == otherdevices_svalues[nomText]) then + --L'action est terminée, on l'efface + debug("####### Fin tâche agenda "..action) + commandArray['UpdateDevice']=idxText.."|0| " + end + end + end + end +end +return commandArray \ No newline at end of file diff --git a/lua/script_time_gestion_batterie.OLD b/lua/script_time_gestion_batterie.OLD new file mode 100755 index 0000000..c5e86b6 --- /dev/null +++ b/lua/script_time_gestion_batterie.OLD @@ -0,0 +1,119 @@ +require "scripts/lua/functions" + +--recupere les minutes +time=os.time() +seconds=tonumber(os.date('%S',time)) +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) +jour=tonumber(os.date('%w',time)) +mois=tonumber(os.date('%M',time)) + +capacite=76 * 12 --Wh +charge=200 --Wh +decharge=50 --Wh +tension_charge_max_off=13.3 +tension_charge_max_on=13.8 +tension_injection_min=11.2 +tension_force_charge=10.8 + +--Initialise la commande de retour finale +commandArray={} + + +-- Tension repos V Conso charge W +-- 11.35 330 +-- 12.35 270 +-- 12.8 233 +-- 12.67 190 +-- 13.33 66 + +-- -------------------------------------------------------------------------------- +-- -------------------------------------------------------------------------------- + +if false and (seconds % 5 == 0 ) then + url = "http://192.168.1.40/getData" + + --result = os.execute(curl..'"'..url..'"') + local jsonContent = getJSONContent(url) + --print(cmd) + + local statuses = decodeJSON(jsonContent) + --printTableAsTree(statuses) + + if isempty(statuses) then + print("BAT ERROR getData") + return commandArray + end + if (otherdevices['ForceChargeBatterie'] == 'On' and + ((tonumber(lastUpdateOfDevice('ForceChargeBatterie')) > 3 * 3600) or tension > tension_charge_max_on)) + then + --commandArray['ForceChargeBatterie'] = "Off" + switchOff("ForceChargeBatterie") + end + + local tension = round(tonumber(statuses['VOLTAGE']) / 55,2) -- tonumber(otherdevices['BatterieTension']) + local power_theorique = -131.71 * tension + 1850.45 + charge=power_theorique + print("BAT Power theorique"..tostring(power_theorique)) + updatenum("BatterieTension", tension) + updatenum("TemperatureBatterie", temperature) + --commandArray['Batterie'] = ternary(statuses['PIN_POWER'] == 0, 'On', 'Off') + --commandArray['InjectionBatterie'] = ternary(statuses['PIN_INJECTION'] == 0, 'On', 'Off') + --commandArray['ChargeBatterie'] = ternary(statuses['PIN_CHARGE'] == 0, 'On', 'Off') + + production = tonumber(split(otherdevices['SolaireProduction'], ";")[1]) + injection = tonumber(split(otherdevices['Injection_Radiateur'], ";")[1]) + chauffe = tonumber(split(otherdevices['Chauffe_Eau'], ";")[1]) + conso = tonumber(split(otherdevices['Consommation_Apparente'], ";")[1]) + print("BAT injection="..tostring(injection) + ..' chauffe='..tostring(chauffe) + ..' charge='..tostring(charge) + ..' conso='..tostring(conso) + .. ' voltage='..tostring(round(tonumber(statuses['VOLTAGE']) / 55,2)) + ..' tension='..tostring(tension) + ) + print("BAT PIN_POWER="..statuses['PIN_POWER'].." PIN_CHARGE="..statuses['PIN_CHARGE'].." PIN_INJECTION="..statuses['PIN_INJECTION'].." PIN_BATTERIE="..statuses['PIN_BATTERIE']) + -- status 0 = ON / 1 = OFF + + if (statuses['PIN_CHARGE'] == 1) then --(otherdevices['ChargeBatterie'] == 'Off') then + if (uservariables['Dark'] == "False" + and (conso < - charge or injection > charge or (injection - conso > charge) or otherdevices['ForceChargeBatterie'] == 'On') + and tension <= tension_charge_max_off + ) + then + print("BAT charge batterie / arret injection") + switchOff("InjectionBatterie") + switchOn("ChargeBatterie") + else + if tension <= tension_force_charge then + switchOn("ForceChargeBatterie") + else + if (statuses['PIN_INJECTION'] == 1) then --(otherdevices['InjectionBatterie'] == 'Off') then + if (conso > decharge and injection < decharge and tension >= tension_injection_min) then + print("BAT Injection batterie / arret charge") + switchOff("ChargeBatterie") + switchOn("InjectionBatterie") + end + else + if (injection > decharge / 2 or conso < - decharge / 2 or tension < tension_injection_min) then -- or (production <= 100 and heures < 23 and heures > 7)) then + print("BAT arret injection batterie") + switchOff("InjectionBatterie") + end + end + end + end + else + -- test sur statuses pour eviter les valeurs nulles + if (conso - injection > 14 or tension > tension_charge_max_on) then + print("BAT arret charge batterie") + switchOff("ChargeBatterie") + --switchOn("InjectionBatterie") + end + end +end + +--if heures == 4 and minutes <= 2 then +-- switchOff("InjectionBatterie") +--end + +return commandArray diff --git a/lua/script_time_gestion_batterie.lua b/lua/script_time_gestion_batterie.lua new file mode 100755 index 0000000..82a468e --- /dev/null +++ b/lua/script_time_gestion_batterie.lua @@ -0,0 +1,56 @@ +require "scripts/lua/functions" + +--recupere les minutes +time=os.time() +seconds=tonumber(os.date('%S',time)) +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) +jour=tonumber(os.date('%w',time)) +mois=tonumber(os.date('%M',time)) + +--Initialise la commande de retour finale +commandArray={} + +-- -------------------------------------------------------------------------------- +-- -------------------------------------------------------------------------------- +if (False and lastUpdateOfDevice('BatterieTension') > 60) then + url = "http://192.168.1.18/getData" + + --result = os.execute(curl..'"'..url..'"') + local jsonContent = getJSONContent(url) + --print(cmd) + + local statuses = decodeJSON(jsonContent) + --printTableAsTree(statuses) + + updatenum("BatterieCharge", 0) + updatenum("BatterieInjection", 0) + if isempty(statuses) then + print("BAT ERROR getData") + return commandArray + end + local tension = round(tonumber(statuses['V']) / 1000,2) -- tonumber(otherdevices['BatterieTension']) + local temperature = round(tonumber(statuses['TEMPERATURE']),1) -- tonumber(otherdevices['BatterieTension']) + + updatenum("BatterieTension", tension) + updatenum("BatterieCharge", tonumber(statuses['PPV'])) + updatenum("TemperatureBatterie", temperature) + + if tension > 20 and tension < 25.4 then + switchOff("Batterie") + -- switchOn("ChargeBatterie") + end +end + + print('Capteur solaire redémarré'..tostring( lastUpdateOfDevice('SolaireProduction').. ' '..tostring(lastUpdateOfDevice('LUMIERE_PLANTE')) )) + +if (lastUpdateOfDevice('Tuya_2') > 60 and lastUpdateOfDevice('LUMIERE_PLANTE') > 60) then + switchOff('LUMIERE_PLANTE') + sleep(3) + switchOn('LUMIERE_PLANTE') + print('Capteur solaire redémarré') +end + + + +return commandArray diff --git a/lua/script_time_livebox.lua b/lua/script_time_livebox.lua new file mode 100755 index 0000000..ca5b10e --- /dev/null +++ b/lua/script_time_livebox.lua @@ -0,0 +1,150 @@ +--------------------------------- +-- Script de détection de présence via livebox +-- Auteur : Sopalin +-- Date : 22 Juillet 2016 +-- Nécessite un switch classique +-- source : + +--------------------------------- +require "scripts/lua/functions" + +--recupere les minutes +time=os.time() +seconds=tonumber(os.date('%S',time)) +minutes=tonumber(os.date('%M',time)) +heures=tonumber(os.date('%H',time)) + + +commandArray={} + +function testActive(name, active) + if active then + --commandArray[name]='On' + switchIfNeeded(name, 'On') + else + switchIfNeeded(name, 'Off') + --commandArray[name]='Off' + end + debug("### Test active Name : "..name.." active "..tostring(active)) +end + +if heures == 8 then + commandArray['Variable:Detection_Manon_20H'] = "0" + commandArray['Variable:Detection_Theo_20H'] = "0" + --uservariables['Detection_Manon_20H'] = 0 + --uservariables['Detection_Theo_20H'] = 0 + --print('Detection_Theo_20H='..string(uservariables['Detection_Theo_20H'])) +end + +--time = os.date("*t") +if (minutes % 5 == 4) then +--if (true) then + + --import des fontions pour lire le JSON + json = (loadfile "/opt/domoticz/scripts/lua/JSON.lua")() + + --Récupération des informations sur la livebox + --Utilisation d'un script VBS sous windows + --Utilisation d'un script bash pour extraire les données + ---------------------------------------------------------------- + --Lecture des données + + local f = assert(io.open("/tmp/Devices.txt","r")) + local livebox = f:read('*all') + f:close() + --Décodage ud fichier + local jsonLivebox = json:decode(livebox) + if jsonLivebox == nil then + return commandArray + end + + --debug("DEBUG") + --debug(timedifference(otherdevices_lastupdate['Presence Thomas'])) + + commandArray['Domi']='Off' + commandArray['Domi_Work']='Off' + commandArray['Theo']='Off' + commandArray['Moi']='Off' + commandArray['Manon']='Off' + commandArray['orangepizero']='Off' + commandArray['jerome']='Off' + commandArray['R53PP2003X0247']='Off' + commandArray['R53PP2003X0247-1']='Off' + + devices = jsonLivebox['status'] + --Parcours du fichier pour vérifier la présence d'un téléphone + for result,status in pairs(devices) do + local name = status['Name'] + debug("Name : "..name.." Mac : "..status['Key'].." "..tostring(status['Active'])) + + if (name == "Akhesa" or name == "Playstation3" or name == "DESKTOP-MUI1HPH" or name == "Theo") then + -- testActive('Theo', status['Active']) + if status['Active'] then + commandArray['Theo']='On' + if heures >= 19 then + commandArray['Variable:Detection_Theo_20H'] = "1" + end + end + end + if (--name == "Nefertiti" or + string.find(name,"Jerome") or name == "Achille" or string.find(name, "Moi") + or name == "iPhonedeJerome" or name == "iPhonedeJerome-1" or name == "jerome" + or name == "Iphone-jerome" + ) then + if status['Active'] then + commandArray['Moi']='On' + end + end + if (name == "DomiPro" or name == "Domi") then + -- testActive('Domi', status['Active']) + if status['Active'] then + commandArray['Domi']='On' + end + end + if (name == "R53PP2003X0247-1" or name == "R53PP2003X0247") then + if status['Active'] then + commandArray['Domi_Work']='On' + end + end + if (name == "Akhenaton-3" or name == "Akhenaton") then + testActive("Akhenaton", status['Active']) + end + if (name == "Manon" or name == "AcerManon" + or name == "DESKTOP-KH8V15B" or name == "iPhone-de-Manon" or name == "IPhonedeManon") + then + -- testActive("Manon", status['Active']) + if status['Active'] then + commandArray['Manon']='On' + if heures >= 20 then + commandArray['Variable:Detection_Manon_20H'] = "1" + end + end + end + + if (name == "TeleChambre" or name == "AcerManon" or name == "Akhesa" or name == "AkhesaNew" + or name == "Akhenaton" or name == "SoutiHP" or name == "Hackintosh" + or name == "Octoprint" or name == "jerome" + or name == "Volumio" or name == "LibreELEC" + or name == "Recovery") then + testActive(name, status['Active']) + end + + if (--name == "orangepizero" or name == "orangepizero-1" or + name == "orangepizero-2") then + if status['Active'] then + commandArray['orangepizero']='On' + end + end + + if (name == "RadiateurManon" or name == "RadiateurTheo" or name == "RadiateurBureau" + or name == "RadiateurChambre") then + if status['Active'] then + -- nothing + else + -- commandArray['SendNotification']='Alerte radiateur '..name..'#Alerte radiateur ne repond pas au ping '..name + end + end + end +end + +return commandArray diff --git a/lua/script_time_variables.lua b/lua/script_time_variables.lua new file mode 100755 index 0000000..1e834dd --- /dev/null +++ b/lua/script_time_variables.lua @@ -0,0 +1,139 @@ +require "scripts/lua/functions" + +---------------------------------------------------------------------------------------------------------- +-- Script parameters +---------------------------------------------------------------------------------------------------------- +-- Setting the time variables: +-- %a abbreviated weekday name (e.g., Wed) +-- %A full weekday name (e.g., Wednesday) +-- %b abbreviated month name (e.g., Sep) +-- %B full month name (e.g., September) +-- %c date and time (e.g., 09/16/98 23:48:10) +-- %d day of the month (16) [01-31] +-- %H hour, using a 24-hour clock (23) [00-23] +-- %I hour, using a 12-hour clock (11) [01-12] +-- %M minute (48) [00-59] +-- %m month (09) [01-12] +-- %p either "am" or "pm" (pm) +-- %S second (10) [00-61] +-- %w weekday (3) [0-6 = Sunday-Saturday] +-- %x date (e.g., 09/16/98) +-- %X time (e.g., 23:48:10) +-- %Y full year (1998) +-- %y two-digit year (98) [00-99] +-- %% the character `%´ + +year = tonumber(os.date("%Y")); +month = tonumber(os.date("%m")); +day = tonumber(os.date("%d")); +hour = tonumber(os.date("%H")); +min = tonumber(os.date("%M")); +weekday = tonumber(os.date("%w")); + +---------------------------------------------------------------------------------------------------------- +-- Script functions +---------------------------------------------------------------------------------------------------------- +function WhichSeason() + local tNow = os.date("*t") + local dayofyear = tNow.yday + local season + if (dayofyear >= 79) and (dayofyear < 172) then season = "Printemps" + elseif (dayofyear >= 172) and (dayofyear < 266) then season = "ete" + elseif (dayofyear >= 266) and (dayofyear < 355) then season = "Automne" + else season = "Hiver" + end + return season +end + +function IsWeekend() + local dayNow = tonumber(os.date("%w")) + local weekend + if (dayNow == 0) or (dayNow == 6) then weekend = "True" + else weekend = "False" + end + return weekend +end + + +function IsDark() + local dark + -- local now = heureEnMinute(uservariables["Couche"]) - 30 + local now = 60 * hour + min - 15 + local now2 = 60 * hour + min + 15 + + debug (" variable sunset="..tostring(uservariables["Couche"]).." heureEnMinute="..tostring(heureEnMinute(uservariables["Couche"]))) + + local sunsetMin = heureEnMinute(uservariables["Couche"]) + local sunriseMin = heureEnMinute(uservariables["Lever"]) + if (now > sunsetMin --timeofday['SunsetInMinutes'] or + or now2 < sunriseMin --timeofday['SunriseInMinutes'] + ) then -- timeofday['Nighttime']) then + dark = "True" + else + dark = "False" + end + + debug("####### sunset "..tostring(timeofday['SunsetInMinutes'])..' sunrise=' + ..tostring(timeofday['SunriseInMinutes'])..' '..tostring(now)..' '..tostring(dark)) + + return dark +end + +---------------------------------------------------------------------------------------------------------- +-- CommandArray +---------------------------------------------------------------------------------------------------------- + +commandArray = {} +if (min == 10 and hour == 0) then + saison = WhichSeason(); + weekend = IsWeekend(); + if (uservariables["Saison"] ~= season) then commandArray['Variable:Saison'] = tostring(saison) end + if (uservariables["Weekend"] ~= weekend) then commandArray['Variable:Weekend'] = tostring(weekend) end + + debug(' Saison: ' .. saison .. ' '); + debug(' Weekend: ' .. weekend .. ' '); +end + +if (min % 1 == 0 and (hour >= 17 or hour < 10)) then + dark = IsDark(); + if (uservariables["Dark"] ~= dark) then + --commandArray['Variable:Dark'] = tostring(dark) + updateVar("Dark", dark) + + end + debug(' Dark: ' .. dark .. ' '); +end + + +function checkLastUpdate(deviceIDX) + local lastUpdateTime = lastUpdateOfDevice(deviceIDX) + local currentTime = os.time() + local timeDifference = currentTime - lastUpdateTime + + -- Si la dernière mise à jour remonte à plus de 5 minutes + if timeDifference > 300 then + print("Le dispositif n'a pas été mis à jour depuis plus de 5 minutes.") + -- Ajoutez ici le code pour effectuer une action en réponse à l'absence de mise à jour + else + print("Le dispositif a été mis à jour récemment.") + end +end + +if (min % 1 == 0 ) then + checkLastUpdate(1182) +end + +--if otherdevices['Debug'] == 'On' then +-- debug(' Year: ' .. year .. ' '); +-- debug(' Month: ' .. month .. ' '); +-- debug(' Day: ' .. day .. ' '); +-- debug(' Hour: ' .. hour .. ' '); +-- debug(' Minute: ' .. min .. ' '); +-- debug(' Weekday: ' .. weekday .. ' '); +--end + +debug("Updating variables if necessary") + +commandArray['Variable:Heure'] = tostring(hour)..":"..tostring(min) + +return commandArray diff --git a/lua/script_time_variables_Disk.lua b/lua/script_time_variables_Disk.lua new file mode 100755 index 0000000..b0c3cc5 --- /dev/null +++ b/lua/script_time_variables_Disk.lua @@ -0,0 +1,71 @@ +require "scripts/lua/functions" + +---------------------------------------------------------------------------------------------------------- +-- Script parameters +---------------------------------------------------------------------------------------------------------- +-- Setting the time variables: +-- %a abbreviated weekday name (e.g., Wed) +-- %A full weekday name (e.g., Wednesday) +-- %b abbreviated month name (e.g., Sep) +-- %B full month name (e.g., September) +-- %c date and time (e.g., 09/16/98 23:48:10) +-- %d day of the month (16) [01-31] +-- %H hour, using a 24-hour clock (23) [00-23] +-- %I hour, using a 12-hour clock (11) [01-12] +-- %M minute (48) [00-59] +-- %m month (09) [01-12] +-- %p either "am" or "pm" (pm) +-- %S second (10) [00-61] +-- %w weekday (3) [0-6 = Sunday-Saturday] +-- %x date (e.g., 09/16/98) +-- %X time (e.g., 23:48:10) +-- %Y full year (1998) +-- %y two-digit year (98) [00-99] +-- %% the character `%´ + +year = tonumber(os.date("%Y")); +month = tonumber(os.date("%m")); +day = tonumber(os.date("%d")); +hour = tonumber(os.date("%H")); +min = tonumber(os.date("%M")); +weekday = tonumber(os.date("%w")); + + + -- ------------------------------------------------------------------------------ +-- Function test montage +-- ------------------------------------------------------------------------------ +function mountTest(disk) + + local ret = os.execute("mount | grep " .. disk) + debug('######### Lancement du check Disk ' ..disk) + return ret +end + +commandArray = {} + +-- ---------------------- +-- Check disk +-- ---------------------- +if (min % 10 == 0) then + if (isempty(mountTest("WDBlue"))) then + commandArray['Variable:WDBlue'] = 'Off' + else + commandArray['Variable:WDBlue'] = 'On' + end + if (isempty(mountTest("WDGreen"))) then + commandArray['Variable:WDGreen'] = 'Off' + else + commandArray['Variable:WDGreen'] = 'On' + end + if (isempty(mountTest("WDPink"))) then + commandArray['Variable:WDPink'] = 'Off' + else + commandArray['Variable:WDPink'] = 'On' + end + if (isempty(mountTest("WDRed"))) then + commandArray['Variable:WDRed'] = 'Off' + else + commandArray['Variable:WDRed'] = 'On' + end +end +return commandArray diff --git a/lua/script_time_variables_HeureCreuse.lua b/lua/script_time_variables_HeureCreuse.lua new file mode 100755 index 0000000..11cea96 --- /dev/null +++ b/lua/script_time_variables_HeureCreuse.lua @@ -0,0 +1,48 @@ +require "scripts/lua/functions" + +---------------------------------------------------------------------------------------------------------- +-- Script parameters +---------------------------------------------------------------------------------------------------------- +-- Setting the time variables: +-- %a abbreviated weekday name (e.g., Wed) +-- %A full weekday name (e.g., Wednesday) +-- %b abbreviated month name (e.g., Sep) +-- %B full month name (e.g., September) +-- %c date and time (e.g., 09/16/98 23:48:10) +-- %d day of the month (16) [01-31] +-- %H hour, using a 24-hour clock (23) [00-23] +-- %I hour, using a 12-hour clock (11) [01-12] +-- %M minute (48) [00-59] +-- %m month (09) [01-12] +-- %p either "am" or "pm" (pm) +-- %S second (10) [00-61] +-- %w weekday (3) [0-6 = Sunday-Saturday] +-- %x date (e.g., 09/16/98) +-- %X time (e.g., 23:48:10) +-- %Y full year (1998) +-- %y two-digit year (98) [00-99] +-- %% the character `%´ + +year = tonumber(os.date("%Y")); +month = tonumber(os.date("%m")); +day = tonumber(os.date("%d")); +hour = tonumber(os.date("%H")); +min = tonumber(os.date("%M")); +weekday = tonumber(os.date("%w")); + +commandArray = {} + +-- ---------------------- +-- Heures creuses +-- ---------------------- +if (min%10 == 0) then + debug('######### Lancement du check Heures Creuses ' ..hour..'h'..min) + if ((hour > 21 or (hour == 21 and min >= 30)) or (hour < 5 or (hour == 5 and min <= 30))) then + --switchIfNeeded('Variable:HeuresCreuses', 'On') + commandArray['Variable:HeuresCreuses'] = 'On' + else + commandArray['Variable:HeuresCreuses'] = 'Off' + end +end + +return commandArray diff --git a/lua/script_time_volets_duplique.lua b/lua/script_time_volets_duplique.lua new file mode 100755 index 0000000..7573fea --- /dev/null +++ b/lua/script_time_volets_duplique.lua @@ -0,0 +1,471 @@ +require "scripts/lua/functions" + +commandArray = {} + +local HEURE_DEB = 9 +local HEURE_FIN = 17 +local AZIMUTH_FIN = 270 +local TEMP_MAX = 25.5 +local TEMP_MAX_2 = 29 +local MIN_LUX = 15000 +local device_temp = 'BarometreLaGacilly' + +--recupere les minutes +time=os.time() +minutes=tonumber(os.date('%M',time)) +--jour=tonumber(os.date('%w',time)) +heures=tonumber(os.date('%H',time)) +mois=tonumber(os.date('%m',time)) + +local saison = uservariables["Saison"] +local delaiFermeture = uservariables["DelaiFermetureVoletCoucheSoleil"] +local jourS = josdGetJourSemaine() +local nuages = tonumber(otherdevices['Nuage_LaGacilly']) +local temp_ext = getExternalTempRef(device_temp) + +-- ------------------------------------------------------------------- +-- Verification des volets ouverts si température trop basse +-- ------------------------------------------------------------------- +if (minutes == 0 or minutes == 30 ) then + + print('Volets ########## Lancement du check fermeture velux du grenier ' ..heures..'h'..minutes) + + --tab = getValuesInTab('Exterieur_Cellier') + -- val = otherdevices[device_temp] + val, val2 = otherdevices_svalues[device_temp]:match("([^;]+);([^;]+)") + + + local tmp = tonumber(val) + + print('Volets ########## Lancement du check fermeture velux du grenier ' ..heures..'h'..minutes..' tmp='..tostring(tmp)) + + if (tmp < 14.0 and (otherdevices['Velux droit'] == 'Open' or otherdevices['Velux gauche'] == 'Open')) then + commandArray['notification']="Volet ouvert#Un des volets du grenier est reste ouvert #0" + end +end + +-- ----------------------- +-- Fermeture volet central +-- ----------------------- +if minutes%5 == 0 and minutes < 2 + and ( + (heures >= 22 and (saison ~= "ete") and jourS ~= "mercredi" and (mois < 5 or mois >= 9)) -- or uservariables['Dark'] == "True") + or (heures >= 23) + ) +then + print('Volets ------------------------------------------------------') + print('Volets Test fermeture volet Central '..otherdevices['VoletPorteSalon']) + print('Volets ------------------------------------------------------') + if (otherdevices['VoletPorteSalon'] ~= 'Closed') then + commandArray['VoletPorteSalon']='On' + end +end + +-- ----------------------- +-- Ouverture volets +-- ----------------------- +if minutes%10 == 3 + and heures < 10 + and (otherdevices['VoletCuisine'] == 'Closed' or otherdevices['VoletSalonTele'] == 'Closed') + --and (saison == "Printemps" or saison == "ete") +then + print('Volets ------------------------------------------------------') + print('Volets Test ouverture volets jour chome='..tostring(josdJourChome())..' Absence='..otherdevices['AbsenceFamille']..' Vacances='..otherdevices['Vacances'] + ..' '..tostring(heures)..':'..tostring(minutes)) + print('Volets ------------------------------------------------------') + + local ouvertureVolet = false; + if (josdJourChome() + or otherdevices['AbsenceFamille'] == 'On' + or otherdevices['Vacances'] == 'On' + ) then + print('Volets bloc 09:30 '..tostring(heures == 09 and minutes >= 30)) + if (heures == 09 and minutes >= 30) then + ouvertureVolet = true; + end + end + if otherdevices['AbsenceFamille'] == 'Off' + and not josdJourChome() + and otherdevices['Vacances'] == 'Off' + then + print('Volets bloc 07:00 '..tostring(heures == 07 and minutes >= 00)) + if (heures == 07 and minutes >= 00) then + ouvertureVolet = true; + end + end + + print("Volets ouvertureVolet="..tostring(ouvertureVolet)) + if (ouvertureVolet == true) then + print('Volets Ouverture volets jour chome='..tostring(josdJourChome())..' Absence='..otherdevices['AbsenceFamille']..' Vacances='..otherdevices['Vacances'] + ..tostring(heures)..' '..tostring(minutes)) + switchIfNeeded('VoletPorteSalon', 'Off') + switchIfNeeded('VoletSalonTele', 'Off') + switchIfNeeded('VoletCuisine', 'Off') + --if (otherdevices['VoletVelux'] == 'Closed') then + switchIfNeeded('VoletVelux', 'Off') + --end + end +end + +-- ----------------------- +-- Ouverture volets chambres +-- ----------------------- +if minutes%5 == 0 and heures > 6 and heures < 13 + --and (saison == "Printemps" or saison == "ete") +then + print('Volets ------------------------------------------------------') + print('Volets Test ouverture volets chambres') + print('Volets ------------------------------------------------------') + + local presenceManon = (otherdevices['Manon'] == "On" or jourS == "samedi" or (jourS == "dimanche" and heures < 18) or otherdevices['Zone B'] == 'On') + local presenceTheo = (otherdevices['Theo'] == "On" or jourS == "samedi" or (jourS == "dimanche" and heures < 18) or otherdevices['Zone B'] == 'On') + + local val + local val2 + val, val2 = otherdevices_svalues[device_temp]:match("([^;]+);([^;]+)") + --val = otherdevices[device_temp] + + local temp = tonumber(val) + -- ---------------- + -- Volet Somfy + -- ---------------- + if (josdJourChome() or otherdevices['Vacances'] == 'On' + or (otherdevices['Conges'] == 'On' and otherdevices['AbsenceFamille'] == 'Off')) + then + print('Volets Test ouverture volets chambres bloc journee chomee') + if (heures == 10 and minutes >= 30) then + switchIfNeeded('VoletChambreVirtuel', 'Off') + end + if (heures == 12 and minutes >= 30 and minutes <= 32) then + + if (temp >= TEMP_MAX) then + -- nothing + else + switchIfNeeded('VoletManonVirtuel', 'Off') + switchIfNeeded('VoletTheoVirtuel', 'Off') + end + end + else + print('Volets Test ouverture volets chambres bloc journee travaille') + if (heures == 07 and minutes >= 45) then + switchIfNeeded('VoletChambreVirtuel', 'Off') + end + if (heures == 07 and minutes >= 45 and not presenceManon) then + switchIfNeeded('VoletManonVirtuel', 'Off') + end + if (heures == 07 and minutes >= 45 and not presenceTheo) then + switchIfNeeded('VoletTheoVirtuel', 'Off') + end + if (heures == 12 and minutes >= 30 and minutes <= 32) then + if (temp >= TEMP_MAX) then + -- nothing + else + if presenceManon then + switchIfNeeded('VoletManonVirtuel', 'Off') + end + if presenceTheo then + switchIfNeeded('VoletTheoVirtuel', 'Off') + end + + end + end + end +end + +if minutes%1 == 0 and heures >= 19 and (saison == "ete") + and uservariables['VoletsSomfy'] ~= 'open' + and uservariables['Dark'] ~= "True" +then + + local evolution = tonumber(uservariables['AugmentationTempExterieure']) + + local tempChambre = getTemperatureFromDevice('Chambre') + + print("tempChambre="..tostring(tempChambre).." temp_ext="..tostring(temp_ext).." evolution="..tostring(evolution)) + + if (temp_ext + evolution <= tempChambre) then + commandArray['Variable:VoletsSomfy'] = "open" + + print("SOMFY Volets test ouverture volets : temp en baisse") + print("SOMFY Volets Lancement script somfy") + + os.execute("/opt/domoticz/scripts/voletsSomfy.sh u") + end +end + +-- --------------------------------------------------------------------------------------- +-- Fermeture des volets +-- --------------------------------------------------------------------------------------- +--print("Volets DARK=="..tostring(uservariables['Dark'] == "True")) +if minutes%5 == 0 + -- (saison ~= "Ete") + and ( + otherdevices['VoletCuisine'] == 'Open' or otherdevices['VoletSalonTele'] == 'Open' + --or otherdevices['VoletChambreVirtuel'] == 'Open' + --or otherdevices['VoletManonVirtuel'] == 'Open' + --or otherdevices['VoletTheoVirtuel'] == 'Open' + ) + and (heures >= 18 or + ( + (heures >= 17 and minutes >= 30) and ( + uservariables['Dark'] == "True" + or ( + tonumber(otherdevices['Lux']) < tonumber(uservariables["LuxMini"]) + ) + ) + ) + ) +then + print('Volets ------------------------------------------------------') + print('Volets Test fermeture volet ') + print('Volets ------------------------------------------------------') + + print('Volets ####### Comparaison heure vs Couche du soleil ========>'..uservariables["Heure"].." couché "..uservariables["Couche"]) + --print('Volets ####### Lancement du check test ' ..heures..'h'..minutes..' volet cuisine '..otherdevices['Exterieur_Cellier']..' svalues='..otherdevices_svalues['Exterieur_Cellier']..' VoletCuisine='..otherdevices['VoletCuisine']) + --tmp = otherdevices_svalues['Exterieur_Cellier'] + --tab = split(tmp, ";") + + -- val = otherdevices[device_temp] + print("Volets ######### Check fermeture : temperature lue par "..device_temp.." "..temp_ext) + + temp = temp_ext --tonumber(val) + + if ( + ( + ( + (temp < 6.0 and whenDark() <= 0) + or (temp < 8 and whenDark() <= -10) + or (temp < 10 and whenDark() <= -20) + ) + ) + or ( + uservariables['Dark'] == "True" + ) + ) + then + local temp_chambre = getTemperatureFromDevice('Chambre') + + print(temp_chambre) + + print("Volets ######### Dans temperature exterieure la gacilly "..tostring(temp_ext)..' temp_chambre'..tostring(temp_chambre)) + if mois >= 6 and mois <= 9 and temp_ext < temp_chambre and temp_ext >= 21 and temp_chambre > 23 then + if (otherdevices['VoletCuisine'] == 'Open' and otherdevices['VoletSalonTele'] == 'Open') then -- or (minutes % 10 == 0 and heures <=20)) then + print("Volets Lancement volets2 On 17") + os.execute("/opt/domoticz/scripts/volets2.sh On 17 &") + end + else + print("Volets Lancement un par un") + + if (otherdevices['VoletCuisine'] == 'Open') then -- or (minutes % 10 == 0 and heures <=20) ) then + commandArray['VoletCuisine']='On' + end + if (otherdevices['VoletSalonTele'] == 'Open') then -- or (minutes % 10 == 0 and heures <=20)) then + commandArray['VoletSalonTele']='On' + end + if (otherdevices['VoletChambreVirtuel'] == 'Open') then -- or (minutes % 10 == 0 and heures <=20)) then + commandArray['VoletChambreVirtuel']='On' + end + if (otherdevices['VoletManonVirtuel'] == 'Open') then -- or (minutes % 10 == 0 and heures <=20)) then + commandArray['VoletManonVirtuel']='On' + end + if (otherdevices['VoletTheoVirtuel'] == 'Open') then -- or (minutes % 10 == 0 and heures <=20)) then + commandArray['VoletTheoVirtuel']='On' + end + end + switchIfNeeded('VoletVelux', 'On') + else + print("Volets ############ PAS DANS LE IF") + end + +end + +-- ------------------------------------------------------------------------------ +-- Ouverture des volets en fonction de la temperature exterieure Hiver et Automne +-- ------------------------------------------------------------------------------ +if minutes%5 == 0 + and heures <= HEURE_DEB + and ((heures >= 9 and josdJourChome()) or (heures > 6 and not josdJourChome())) + and (saison == "Hiver" or saison == "Automne") + and (greater2(uservariables["Heure"],uservariables["Lever"], - 30)) -- heures >= 20 + and (otherdevices['VoletCuisine'] == 'Closed' + or otherdevices['VoletSalonTele'] == 'Closed' + or otherdevices['VoletPorteSalon'] == 'Closed' + or otherdevices['VoletVelux'] == 'Closed' + or otherdevices['VoletChambreVirtuel'] == 'Closed' + or otherdevices['VoletManonVirtuel'] == 'Closed' + or otherdevices['VoletTheoVirtuel'] == 'Closed' + ) +then + print('Volets ------------------------------------------------------') + print('Volets Test ouverture volet ') + print('Volets ------------------------------------------------------') + + print('Volets ####### Comparaison heure vs Lever du soleil ========>'..uservariables["Heure"].. + " "..uservariables["Lever"]) + print('Volets ####### Lancement du check test ' ..heures..'h'..minutes..' volet cuisine ' + ..otherdevices['Exterieur_Cellier']..' svalues='..otherdevices_svalues[device_temp]..' VoletCuisine='..otherdevices['VoletCuisine']) + + temp = temp_ext -- + if (temp > 12.0 + or (heures >=9 and minutes >= 30 and josdJourChome()) + or (heures > 6 and not josdJourChome()) + ) then + if (otherdevices['VoletCuisine'] == 'Closed' or (minutes % 10 == 0 and heures == 9)) then + commandArray ['VoletCuisine']='Off' + end + if (otherdevices['VoletSalonTele'] == 'Closed' or (minutes % 10 == 0 and heures == 9)) then + commandArray['VoletSalonTele']='Off' + end + if (otherdevices['VoletPorteSalon'] == 'Closed' or (minutes % 10 == 0 and heures == 9)) then + commandArray['VoletPorteSalon']='Off' + end + if (otherdevices['VoletVelux'] == 'Closed' or (minutes % 10 == 0 and heures == 9)) then + commandArray['VoletVelux']='Off' + end +-- if (otherdevices['VoletChambreVirtuel'] == 'Closed') then -- or (minutes % 10 == 0 and heures <=20)) then +-- commandArray['VoletChambreVirtuel']='Off' +-- end +-- if (otherdevices['VoletManonVirtuel'] == 'Closed') then -- or (minutes % 10 == 0 and heures <=20)) then +-- commandArray['VoletManonVirtuel']='Off' +-- end +-- if (otherdevices['VoletTheoVirtuel'] == 'Closed') then -- or (minutes % 10 == 0 and heures <=20)) then +-- commandArray['VoletTheoVirtuel']='Off' +-- end + end +end + +-- ------------------------------------------------------------------------------ +-- fermeture des volets en fonction de la temperature exterieure en ete +-- ------------------------------------------------------------------------------ +if (minutes%5 == 0 --and uservariables['Dark'] == "False" +and (heures > HEURE_DEB and heures < HEURE_FIN)) +--and (saison == "ete") +--and (greater(uservariables["Heure"] , uservariables["Lever"])) -- heures >= 20 +--and (otherdevices['VoletCuisine'] == 'Open' or otherdevices['VoletSalonTele'] == 'Open' or otherdevices['VoletPorteSalon'] == 'Open') +then + print('Volets ------------------------------------------------------') + print('Volets Test fermeture volet Ete') + print('Volets ------------------------------------------------------') + + print('Volets ####### Lancement du check test ' ..heures..'h'..minutes.. + ' temp cellier '..otherdevices['Exterieur_Cellier'].. + ' svalues='..otherdevices_svalues[device_temp].. + ' VoletCuisine='..otherdevices['VoletCuisine'].. + ' nuages='..tostring(nuages)) + + local temp = temp_ext + if (saison == "ete" or temp >= TEMP_MAX) then + -- Lecture des lux pour ne pas fermer si ciel couvert + -- local lux = tonumber(otherdevices['Lux']) + + print("Volets "..device_temp.." "..otherdevices_svalues[device_temp] + .." volet cuisine "..otherdevices['VoletCuisine'].. + " volet tele "..otherdevices['VoletSalonTele'].. + " volet salon"..otherdevices['VoletPorteSalon']) + + if temp >= TEMP_MAX + and (otherdevices['VoletCuisine'] == 'Open' + and otherdevices['VoletSalonTele'] == 'Open' + and otherdevices['VoletPorteSalon'] == 'Open') + --and tonumber(otherdevices['Sun Altitude']) > 50 + --sand (nuages < 50 or temp >= TEMP_MAX_2) + then + commandArray['Variable:VoletsSomfy'] = "close" + + print("Volets test fermeture volets : temp élevée lux"..tostring(lux)) + -- if lux > MIN_LUX then + if temp >= TEMP_MAX_2 then + print("Volets Lancement script 2 temp élevée volets2.sh on 15") + + os.execute("/opt/domoticz/scripts/volets2.sh On 15 &") + else + print("Volets Lancement script 1 temp élevée volets.sh on ") + + os.execute("/opt/domoticz/scripts/volets.sh On &") + end + -- end + end + end + if (temp >= TEMP_MAX_2 and heures == 13 and minutes == 00 + and jours ~= 'samedi' and jours ~= "dimanche" + ) then + commandArray['Variable:VoletsSomfy'] = "close" + + print("Volets test fermeture volets : temp très élevée lux"..tostring(lux)) + print("Volets Lancement script somfy") + + os.execute("/opt/domoticz/scripts/voletsSomfy.sh d") + -- end + end +end + + +-- print("Volets Sun Altitude=" ..otherdevices['Sun Altitude']) + +-- ------------------------------------------------------------------------------ +-- Réouverture après la vague de chaleur ETE +-- ------------------------------------------------------------------------------ +-- print("Volets Azimuth="..otherdevices["Sun Azimuth"]) +if (minutes%5 == 0 + and ((heures > HEURE_FIN and whenDark() > 60)) --heures <= 19)) + and (saison == "ete" or (mois >= 5 and mois <= 10 )) +) then + + -- val = otherdevices[device_temp] + + print("Volets -- ------------------------------------------------------------------------------") + print("Volets -- Réouverture après la vague de chaleur ETE") + print("Volets -- ------------------------------------------------------------------------------") + + print("Volets "..device_temp.." "..otherdevices["Exterieur_Cellier"].." "..tostring(temp_ext).. + otherdevices['VoletCuisine'].." "..otherdevices['VoletSalonTele'].." "..otherdevices['VoletPorteSalon']) + + local temp = temp_ext + + if ((temp <= 26 or (temp <= TEMP_MAX and heures >= 18) or (heures >= 19) + or tonumber(otherdevices['Sun Altitude']) <= 30 + ) + --or tonumber(otherdevices["Sun Azimuth"]) > AZIMUTH_FIN) + and (otherdevices['VoletCuisine'] == 'Closed' or + otherdevices['VoletSalonTele'] == 'Closed' or + otherdevices['VoletPorteSalon'] == 'Closed')) + then + print("Volets Ouverture volets : temp en baisse") + if temp <= TEMP_MAX then + print("Volets Lancement volets2 Off 20") + + os.execute("/opt/domoticz/scripts/volets2.sh Off 20 &") + else + print("Volets Lancement volets3 Off 20") + + os.execute("/opt/domoticz/scripts/volets3.sh Off 20 &") + + end + end + +end + +-- ------------------------------------------------------------------------------ +-- Activation ventilation grenier +-- ------------------------------------------------------------------------------ +if (minutes%5 == 0 +) then + local temp = tonumber(otherdevices_svalues['Cheminee']) + + print("Volets "..device_temp.." Test ventilation "..otherdevices_svalues[device_temp].." externe="..temp_ext.." salon="..temp) + + local variation = variationTemp2('Cheminee', 30) -- variation des 10 dernières minutes + print("Variation Chemine="..tostring(variation)) + + if (temp_ext < 15 and (temp >= 20 or variation > 1) and heures >= 10) then + print("Activation ventilation") + commandArray['Ventilation'] = 'On' + else + print("Désactivation ventilation") + commandArray['Ventilation'] = 'Off' + end + +end + + +return commandArray diff --git a/lua/sqlite.lua b/lua/sqlite.lua new file mode 100755 index 0000000..a08e23e --- /dev/null +++ b/lua/sqlite.lua @@ -0,0 +1,18 @@ +-- Ne fonctionne plus require "luasql.sqlite3" + +luasql = require "luasql.sqlite3" + +env = luasql.sqlite3() +conn = env:connect("/opt/domoticz/domoticz.db") + +cursor = assert(conn:execute("select temperature,date from temperature where devicerowid = 101 order by date desc limit 10")) +row = {} +while cursor:fetch(row) do + print(table.concat(row, '|')) +end + +cursor:close() +conn:close() + +env:close() + diff --git a/lua/test.lua b/lua/test.lua new file mode 100755 index 0000000..f784660 --- /dev/null +++ b/lua/test.lua @@ -0,0 +1,112 @@ +-- script domoticz/scripts/lua/script_device_compteurHC-HP.lua + +-- Initialisation des variables locales +local capteurGlobal = uservariables['Capteur électricité'] +local capteurCptHP = uservariables['ConsoCapteurHP'] +local capteurCptHC = uservariables['ConsoCapteurHC'] +local idxCptHP = uservariables['IdxCptHP'] +local idxCptHC = uservariables['IdxCptHC'] +local flagHC = uservariables['FlagHC'] +local flagHP = uservariables['FlagHP'] +local lastValueCptElecGlobal = uservariables['LastValueCptElecGlobal'] + +-- Mode debug Oui / Non +local debug = uservariables['debug'] + +-- Fonction de mise à jour +function update(device, id, power, energy, index) + commandArray[index] = {['UpdateDevice'] = id .. "|0|" .. power .. ";" .. energy} + return +end + +commandArray = {} + +-- On prend en compte a chaque changement de valeur du compteur global +if (devicechanged[capteurGlobal]) then + if (debug == 'OUI') then + print('-- Calcul Compteurs HC / HP --') + print('CapteurGlobal = '..capteurGlobal) + print('CapteurCptHP = '..capteurCptHP) + print('CapteurCptHC = '..capteurCptHC) + print('idxCptHP = '..tostring(idxCptHP)) + print('idxCptHC = '..tostring(idxCptHC)) + print('flagHP = '..tostring(flagHP)) + print('flagHC = '..tostring(flagHC)) + print('LastValueCptElecGlobal = '..tostring(lastValueCptElecGlobal)) + end + + -- Recuperation des valeurs du compteur global + local consoCumule + local consoInstant + consoInstant, consoCumule = otherdevices_svalues[capteurGlobal]:match("([^;]+);([^;]+)") + consoInstant = tonumber(consoInstant) + consoCumule = tonumber(consoCumule) + + if (debug == 'OUI') then + print('Conso Instant = '..tostring(consoInstant)..' / Conso Cumule = '..tostring(consoCumule)..' ') + end + + -- Calcul de l'ecart avec le dernier envoi de donnees + lastValueCptElecGlobal = tonumber(lastValueCptElecGlobal) + local consoDelta = consoCumule - lastValueCptElecGlobal + + if (debug == 'OUI') then + print('Delta conso = '..tostring(consoDelta)) + end + + local consoCumuleCible + local consoInstantCible + + if (otherdevices[flagHC] == 'On') then + -- Periode heures creuse + -- Recuperation des valeurs du compteur global + consoInstantCible, consoCumuleCible = otherdevices_svalues[capteurCptHC]:match("([^;]+);([^;]+)") + -- Seul le cumule du compteur nous interesse pour calculer la nouvelle valeur + consoCumuleCible = tonumber(consoCumuleCible) + + if (debug == 'OUI') then + print('Compteur cible = HC') + print('Valeur precedente = '..tostring(consoCumuleCible)) + print('Valeur ajustee = '..tostring(consoCumuleCible + consoDelta)) + end + + consoCumuleCible = consoCumuleCible + consoDelta + -- Mise à jour du compteur + update(capteurCptHC, idxCptHC, consoInstant, consoCumuleCible, 1) + + -- Mise à 0 de la conso intantanee du compteur HP + consoInstantHP, consoCumuleHP = otherdevices_svalues[capteurCptHP]:match("([^;]+);([^;]+)") + consoInstantHP = 0 + update(capteurCptHP, idxCptHP, consoInstantHP, consoCumuleHP, 2) + else + -- Periode heures pleines + -- Recuperation des valeurs du compteur global + consoInstantCible, consoCumuleCible = otherdevices_svalues[capteurCptHP]:match("([^;]+);([^;]+)") + -- Seul le cumule du compteur nous interesse pour calculer la nouvelle valeur + consoCumuleCible = tonumber(consoCumuleCible) + + if (debug == 'OUI') then + print('Compteur cible = HP') + print('Valeur precedente = '..tostring(consoCumuleCible)) + print('Valeur ajustee = '..tostring(consoCumuleCible + consoDelta)) + end + + consoCumuleCible = consoCumuleCible + consoDelta + -- Mise à jour du compteur + update(capteurCptHP, idxCptHP, consoInstant, consoCumuleCible, 3) + + -- Mise à 0 de la conso intantanee du compteur HC + consoInstantHC, consoCumuleHC = otherdevices_svalues[capteurCptHC]:match("([^;]+);([^;]+)") + consoInstantHC = 0 + update(capteurCptHC, idxCptHC, consoInstantHC, consoCumuleHC, 4) + end + + -- Sauvegarde de la valeur du compteur global pour prochain calcul + commandArray['Variable:LastValueCptElecGlobal'] = tostring(consoCumule) + + if (debug == 'OUI') then + print('-- Fin Calcul Compteur HC / HP --') + end +end + +return commandArray diff --git a/lua/vigilance.html b/lua/vigilance.html new file mode 100644 index 0000000..baad12f --- /dev/null +++ b/lua/vigilance.html @@ -0,0 +1,533 @@ + + + + + + + + + +

Carte de vigilance des pollens - valable jusqu'au 23 mars.

+

Survolez le dpartement de votre choix pour connatre le risque
d'allergie pour chaque pollen.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + + + + +
+
+

Quels pollens pour la Saint-Patrick ?

+

Pour la fte de la Saint-Patrick, les pollens de cyprs seront de sortie surtout dans le sud du pays avec un risque d'allergie maximal tout autour de la Mditerrane.
+En attendant l'arrive des pollens de bouleau (annonce pour la fin du mois), il faudra se mfier des pollens d'aulne qui sont de la mme famille et gneront fortement les allergiques sur l'ensemble du territoire avec un risque moyen localement lev comme dans plusieurs dpartements du Nord-Est, du Centre et de l'Est.
+Les noisetiers quant eux risquent de rater la Saint-Patrick car ils sont en fin de pollinisation avec un risque d'allergie ne dpassant pas le niveau faible tandis que les pollens de frne gagnent du terrain et envahissent le pays avec des quantits partout en augmentation mais un risque globalement faible. Les pollens de peuplier et de saule seront aussi prsents sur l'ensemble du pays mais ils ne sont pas trs allergisants et ils gneront peu les allergiques.
+Les pollens de gramines continuent gagner du terrain par le sud-ouest avec un risque associ de niveau faible.
+Les averses orageuses et le froid limiteront la dispersion des pollens ces prochains jours mais le retour du beau temps sur toute la France ds lundi fera repartir la hausse les quantits de pollens.
+Les allergiques devront rester vigilants et bien suivre leurs traitements ou consulter leur mdecin en cas de symptmes. +

+

 

+

Risque d'allergie *

+

: nul : trs faible : faible : moyen : lev : trs lev

+

* Le risque d'allergie prvisionnel est tabli partir des quantits de pollens mesures, des prvisions mtorologiques pour les jours venir, du stade phnologique des vgtaux et de l'intensit des symptmes constats par les mdecins chez leurs patients allergiques aux pollens.

+
+ + +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ + \ No newline at end of file diff --git a/lua/xml2lua.lua b/lua/xml2lua.lua new file mode 100644 index 0000000..053af93 --- /dev/null +++ b/lua/xml2lua.lua @@ -0,0 +1,213 @@ +--- @module Module providing a non-validating XML stream parser in Lua. +-- +-- Features: +-- ========= +-- +-- * Tokenises well-formed XML (relatively robustly) +-- * Flexible handler based event API (see below) +-- * Parses all XML Infoset elements - ie. +-- - Tags +-- - Text +-- - Comments +-- - CDATA +-- - XML Decl +-- - Processing Instructions +-- - DOCTYPE declarations +-- * Provides limited well-formedness checking +-- (checks for basic syntax & balanced tags only) +-- * Flexible whitespace handling (selectable) +-- * Entity Handling (selectable) +-- +-- Limitations: +-- ============ +-- +-- * Non-validating +-- * No charset handling +-- * No namespace support +-- * Shallow well-formedness checking only (fails +-- to detect most semantic errors) +-- +-- API: +-- ==== +-- +-- The parser provides a partially object-oriented API with +-- functionality split into tokeniser and handler components. +-- +-- The handler instance is passed to the tokeniser and receives +-- callbacks for each XML element processed (if a suitable handler +-- function is defined). The API is conceptually similar to the +-- SAX API but implemented differently. +-- +-- XML data is passed to the parser instance through the 'parse' +-- method (Note: must be passed a single string currently) +-- +-- License: +-- ======== +-- +-- This code is freely distributable under the terms of the [MIT license](LICENSE). +-- +-- +--@author Paul Chakravarti (paulc@passtheaardvark.com) +--@author Manoel Campos da Silva Filho +local xml2lua = {} +local XmlParser = require("XmlParser") + +---Recursivelly prints a table in an easy-to-ready format +--@param tb The table to be printed +--@param level the indentation level to start with +local function printableInternal(tb, level) + if tb == nil then + return + end + + level = level or 1 + local spaces = string.rep(' ', level*2) + for k,v in pairs(tb) do + if type(v) == "table" then + print(spaces .. k) + printableInternal(v, level+1) + else + print(spaces .. k..'='..v) + end + end +end + +---Instantiates a XmlParser object to parse a XML string +--@param handler Handler module to be used to convert the XML string +--to another formats. See the available handlers at the handler directory. +-- Usually you get an instance to a handler module using, for instance: +-- local handler = require("xmlhandler/tree"). +--@return a XmlParser object used to parse the XML +--@see XmlParser +function xml2lua.parser(handler) + if handler == xml2lua then + error("You must call xml2lua.parse(handler) instead of xml2lua:parse(handler)") + end + + local options = { + --Indicates if whitespaces should be striped or not + stripWS = 1, + expandEntities = 1, + errorHandler = function(errMsg, pos) + error(string.format("%s [char=%d]\n", errMsg or "Parse Error", pos)) + end + } + + return XmlParser.new(handler, options) +end + +---Recursivelly prints a table in an easy-to-ready format +--@param tb The table to be printed +function xml2lua.printable(tb) + printableInternal(tb) +end + +---Handler to generate a string prepresentation of a table +--Convenience function for printHandler (Does not support recursive tables). +--@param t Table to be parsed +--@return a string representation of the table +function xml2lua.toString(t) + local sep = '' + local res = '' + if type(t) ~= 'table' then + return t + end + + for k,v in pairs(t) do + if type(v) == 'table' then + v = xml2lua.toString(v) + end + res = res .. sep .. string.format("%s=%s", k, v) + sep = ',' + end + res = '{'..res..'}' + + return res +end + +--- Loads an XML file from a specified path +-- @param xmlFilePath the path for the XML file to load +-- @return the XML loaded file content +function xml2lua.loadFile(xmlFilePath) + local f, e = io.open(xmlFilePath, "r") + if f then + --Gets the entire file content and stores into a string + return f:read("*a") + end + + error(e) +end + +---Gets an _attr element from a table that represents the attributes of an XML tag, +--and generates a XML String representing the attibutes to be inserted +--into the openning tag of the XML +-- +--@param attrTable table from where the _attr field will be got +--@return a XML String representation of the tag attributes +local function attrToXml(attrTable) + local s = "" + local attrTable = attrTable or {} + + for k, v in pairs(attrTable) do + s = s .. " " .. k .. "=" .. '"' .. v .. '"' + end + return s +end + +---Gets the first key of a given table +local function getFirstKey(tb) + if type(tb) == "table" then + for k, v in pairs(tb) do + return k + end + return nil + end + + return tb +end + +---Converts a Lua table to a XML String representation. +--@param tb Table to be converted to XML +--@param tableName Name of the table variable given to this function, +-- to be used as the root tag. +--@param level Only used internally, when the function is called recursively to print indentation +-- +--@return a String representing the table content in XML +function xml2lua.toXml(tb, tableName, level) + local level = level or 0 + local firstLevel = level + local spaces = string.rep(' ', level*2) + local xmltb = level == 0 and {'<'..tableName..'>'} or {} + + for k, v in pairs(tb) do + if type(v) == "table" then + --If the keys of the table are a number, it represents an array + if type(k) == "number" then + local attrs = attrToXml(v._attr) + v._attr = nil + table.insert(xmltb, + spaces..'<'..tableName..attrs..'>\n'..xml2lua.toXml(v, tableName, level+1).. + '\n'..spaces..'') + else + level = level + 1 + if type(getFirstKey(v)) == "number" then + table.insert(xmltb, spaces..xml2lua.toXml(v, k, level)) + else + table.insert( + xmltb, + spaces..'<'..k..'>\n'.. xml2lua.toXml(v, level+1).. + '\n'..spaces..'') + end + end + else + table.insert(xmltb, spaces..'<'..k..'>'..tostring(v)..'') + end + end + + if firstLevel == 0 then + table.insert(xmltb, '\n') + end + return table.concat(xmltb, "\n") +end + +return xml2lua diff --git a/lua/xmlhandler/dom.lua b/lua/xmlhandler/dom.lua new file mode 100644 index 0000000..94470a8 --- /dev/null +++ b/lua/xmlhandler/dom.lua @@ -0,0 +1,136 @@ +---- @module Handler to generate a DOM-like node tree structure with +-- a single ROOT node parent - each node is a table comprising +-- the fields below. +-- +-- node = { _name = , +-- _type = ROOT|ELEMENT|TEXT|COMMENT|PI|DECL|DTD, +-- _attr = { Node attributes - see callback API }, +-- _parent = +-- _children = { List of child nodes - ROOT/NODE only } +-- } +-- where: +-- - PI = XML Processing Instruction tag. +-- - DECL = XML declaration tag +-- +-- The dom structure is capable of representing any valid XML document +-- +-- Options +-- ======= +-- options.(comment|pi|dtd|decl)Node = bool +-- - Include/exclude given node types +-- +-- License: +-- ======== +-- +-- This code is freely distributable under the terms of the [MIT license](LICENSE). +-- +--@author Paul Chakravarti (paulc@passtheaardvark.com) +--@author Manoel Campos da Silva Filho +local dom = { + options = {commentNode=1, piNode=1, dtdNode=1, declNode=1}, + current = { _children = {n=0}, _type = "ROOT" }, + _stack = {} +} + +---Parses a start tag. +-- @param tag a {name, attrs} table +-- where name is the name of the tag and attrs +-- is a table containing the atributtes of the tag +function dom:starttag(tag) + local node = { _type = 'ELEMENT', + _name = tag.name, + _attr = tag.attrs, + _children = {n=0} + } + + if self.root == nil then + self.root = node + end + + table.insert(self._stack, node) + + table.insert(self.current._children, node) + self.current = node +end + +---Parses an end tag. +-- @param tag a {name, attrs} table +-- where name is the name of the tag and attrs +-- is a table containing the atributtes of the tag +function dom:endtag(tag, s) + --Table representing the containing tag of the current tag + local prev = self._stack[#self._stack] + + if tag.name ~= prev._name then + error("XML Error - Unmatched Tag ["..s..":"..tag.name.."]\n") + end + + table.remove(self._stack) + self.current = self._stack[#self._stack] +end + +---Parses a tag content. +-- @param text text to process +function dom:text(text) + local node = { _type = "TEXT", + _text = text + } + table.insert(self.current._children, node) +end + +---Parses a comment tag. +-- @param text comment text +function dom:comment(text) + if self.options.commentNode then + local node = { _type = "COMMENT", + _text = text + } + table.insert(self.current._children, node) + end +end + +--- Parses a XML processing instruction (PI) tag +-- @param tag a {name, attrs} table +-- where name is the name of the tag and attrs +-- is a table containing the atributtes of the tag +function dom:pi(tag) + if self.options.piNode then + local node = { _type = "PI", + _name = tag.name, + _attr = tag.attrs, + } + table.insert(self.current._children, node) + end +end + +---Parse the XML declaration line (the line that indicates the XML version). +-- @param tag a {name, attrs} table +-- where name is the name of the tag and attrs +-- is a table containing the atributtes of the tag +function dom:decl(tag) + if self.options.declNode then + local node = { _type = "DECL", + _name = tag.name, + _attr = tag.attrs, + } + table.insert(self.current._children, node) + end +end + +---Parses a DTD tag. +-- @param tag a {name, attrs} table +-- where name is the name of the tag and attrs +-- is a table containing the atributtes of the tag +function dom:dtd(tag) + if self.options.dtdNode then + local node = { _type = "DTD", + _name = tag.name, + _attr = tag.attrs, + } + table.insert(self.current._children, node) + end +end + +---Parses CDATA tag content. +dom.cdata = dom.text +return dom diff --git a/lua/xmlhandler/print.lua b/lua/xmlhandler/print.lua new file mode 100644 index 0000000..34f3f1f --- /dev/null +++ b/lua/xmlhandler/print.lua @@ -0,0 +1,108 @@ +---@module Handler to generate a simple event trace which +--outputs messages to the terminal during the XML +--parsing, usually for debugging purposes. +-- +-- License: +-- ======== +-- +-- This code is freely distributable under the terms of the [MIT license](LICENSE). +-- +--@author Paul Chakravarti (paulc@passtheaardvark.com) +--@author Manoel Campos da Silva Filho +local print = {} + +---Parses a start tag. +-- @param tag a {name, attrs} table +-- where name is the name of the tag and attrs +-- is a table containing the atributtes of the tag +-- @param s position where the tag starts +-- @param e position where the tag ends +function print:starttag(tag, s, e) + io.write("Start : "..tag.name.."\n") + if tag.attrs then + for k,v in pairs(tag.attrs) do + io.write(string.format(" + %s='%s'\n", k, v)) + end + end +end + +---Parses an end tag. +-- @param tag a {name, attrs} table +-- where name is the name of the tag and attrs +-- is a table containing the atributtes of the tag +-- @param s position where the tag starts +-- @param e position where the tag ends +function print:endtag(tag, s, e) + io.write("End : "..tag.name.."\n") +end + +---Parses a tag content. +-- @param text text to process +-- @param s position where the tag starts +-- @param e position where the tag ends +function print:text(text, s, e) + io.write("Text : "..text.."\n") +end + +---Parses CDATA tag content. +-- @param text CDATA content to be processed +-- @param s position where the tag starts +-- @param e position where the tag ends +function print:cdata(text, s, e) + io.write("CDATA : "..text.."\n") +end + +---Parses a comment tag. +-- @param text comment text +-- @param s position where the tag starts +-- @param e position where the tag ends +function print:comment(text, s, e) + io.write("Comment : "..text.."\n") +end + +---Parses a DTD tag. +-- @param tag a {name, attrs} table +-- where name is the name of the tag and attrs +-- is a table containing the atributtes of the tag +-- @param s position where the tag starts +-- @param e position where the tag ends +function print:dtd(tag, s, e) + io.write("DTD : "..tag.name.."\n") + if tag.attrs then + for k,v in pairs(tag.attrs) do + io.write(string.format(" + %s='%s'\n", k, v)) + end + end +end + +--- Parse a XML processing instructions (PI) tag. +-- @param tag a {name, attrs} table +-- where name is the name of the tag and attrs +-- is a table containing the atributtes of the tag +-- @param s position where the tag starts +-- @param e position where the tag ends +function print:pi(tag, s, e) + io.write("PI : "..tag.name.."\n") + if tag.attrs then + for k,v in pairs(tag.attrs) do + io. write(string.format(" + %s='%s'\n",k,v)) + end + end +end + +---Parse the XML declaration line (the line that indicates the XML version). +-- @param tag a {name, attrs} table +-- where name is the name of the tag and attrs +-- is a table containing the atributtes of the tag +-- @param s position where the tag starts +-- @param e position where the tag ends +function print:decl(tag, s, e) + io.write("XML Decl : "..tag.name.."\n") + if tag.attrs then + for k,v in pairs(tag.attrs) do + io.write(string.format(" + %s='%s'\n", k, v)) + end + end +end + +return print \ No newline at end of file diff --git a/lua/xmlhandler/tree.lua b/lua/xmlhandler/tree.lua new file mode 100644 index 0000000..84ba029 --- /dev/null +++ b/lua/xmlhandler/tree.lua @@ -0,0 +1,159 @@ +local function init() + local obj = { + root = {}, + options = {noreduce = {}} + } + + obj._stack = {obj.root, n=1} + return obj +end + +--- @module XML Tree Handler. +-- Generates a lua table from an XML content string. +-- It is a simplified handler which attempts +-- to generate a more 'natural' table based structure which +-- supports many common XML formats. +-- +-- The XML tree structure is mapped directly into a recursive +-- table structure with node names as keys and child elements +-- as either a table of values or directly as a string value +-- for text. Where there is only a single child element this +-- is inserted as a named key - if there are multiple +-- elements these are inserted as a vector (in some cases it +-- may be preferable to always insert elements as a vector +-- which can be specified on a per element basis in the +-- options). Attributes are inserted as a child element with +-- a key of '_attr'. +-- +-- Only Tag/Text & CDATA elements are processed - all others +-- are ignored. +-- +-- This format has some limitations - primarily +-- +-- * Mixed-Content behaves unpredictably - the relationship +-- between text elements and embedded tags is lost and +-- multiple levels of mixed content does not work +-- * If a leaf element has both a text element and attributes +-- then the text must be accessed through a vector (to +-- provide a container for the attribute) +-- +-- In general however this format is relatively useful. +-- +-- It is much easier to understand by running some test +-- data through 'testxml.lua -simpletree' than to read this) +-- +-- Options +-- ======= +-- options.noreduce = { = bool,.. } +-- - Nodes not to reduce children vector even if only +-- one child +-- +-- License: +-- ======== +-- +-- This code is freely distributable under the terms of the [MIT license](LICENSE). +-- +--@author Paul Chakravarti (paulc@passtheaardvark.com) +--@author Manoel Campos da Silva Filho +local tree = init() + +---Instantiates a new handler object. +--Each instance can handle a single XML. +--By using such a constructor, you can parse +--multiple XML files in the same application. +--@return the handler instance +function tree:new() + local obj = init() + + obj.__index = self + setmetatable(obj, self) + + return obj +end + +--Gets the first key of a table +--@param tb table to get its first key +--@return the table's first key, nil if the table is empty +--or the given parameter if it isn't a table +local function getFirstKey(tb) + if type(tb) == "table" then + for k, v in pairs(tb) do + return k + end + + return nil + end + + return tb +end + +--- Recursively removes redundant vectors for nodes +-- with single child elements +function tree:reduce(node, key, parent) + for k,v in pairs(node) do + if type(v) == 'table' then + self:reduce(v,k,node) + end + end + if #node == 1 and not self.options.noreduce[key] and + node._attr == nil then + parent[key] = node[1] + else + node.n = nil + end +end + +---Parses a start tag. +-- @param tag a {name, attrs} table +-- where name is the name of the tag and attrs +-- is a table containing the atributtes of the tag +function tree:starttag(tag) + local node = {} + if self.parseAttributes == true then + node._attr=tag.attrs + end + + --Table in the stack representing the tag being processed + local current = self._stack[#self._stack] + + if current[tag.name] then + table.insert(current[tag.name], node) + else + current[tag.name] = {node; n=1} + end + + table.insert(self._stack, node) +end + +---Parses an end tag. +-- @param tag a {name, attrs} table +-- where name is the name of the tag and attrs +-- is a table containing the atributtes of the tag +function tree:endtag(tag, s) + --Table in the stack representing the tag being processed + local current = self._stack[#self._stack] + --Table in the stack representing the containing tag of the current tag + local prev = self._stack[#self._stack-1] + if not prev[tag.name] then + error("XML Error - Unmatched Tag ["..s..":"..tag.name.."]\n") + end + if prev == self.root then + -- Once parsing complete, recursively reduce tree + self:reduce(prev, nil, nil) + end + + local firstKey = getFirstKey(current) + table.remove(self._stack) +end + +---Parses a tag content. +-- @param t text to process +function tree:text(text) + local current = self._stack[#self._stack] + table.insert(current, text) +end + +---Parses CDATA tag content. +tree.cdata = tree.text +tree.__index = tree +return tree diff --git a/lua_parsers/.AppleDouble/.Parent b/lua_parsers/.AppleDouble/.Parent new file mode 100644 index 0000000..54f0e0c Binary files /dev/null and b/lua_parsers/.AppleDouble/.Parent differ diff --git a/lua_parsers/.AppleDouble/example.lua b/lua_parsers/.AppleDouble/example.lua new file mode 100644 index 0000000..185f012 Binary files /dev/null and b/lua_parsers/.AppleDouble/example.lua differ diff --git a/lua_parsers/.AppleDouble/example_json.lua b/lua_parsers/.AppleDouble/example_json.lua new file mode 100644 index 0000000..4d931af Binary files /dev/null and b/lua_parsers/.AppleDouble/example_json.lua differ diff --git a/lua_parsers/.AppleDouble/example_owm.lua b/lua_parsers/.AppleDouble/example_owm.lua new file mode 100644 index 0000000..c1bb083 Binary files /dev/null and b/lua_parsers/.AppleDouble/example_owm.lua differ diff --git a/lua_parsers/.AppleDouble/example_xml.lua b/lua_parsers/.AppleDouble/example_xml.lua new file mode 100644 index 0000000..0033c33 Binary files /dev/null and b/lua_parsers/.AppleDouble/example_xml.lua differ diff --git a/lua_parsers/example.lua b/lua_parsers/example.lua new file mode 100644 index 0000000..6900996 --- /dev/null +++ b/lua_parsers/example.lua @@ -0,0 +1,29 @@ +-- Example of parser handling data with the following format +-- TEMPERATURE,HUMIDITY,HUMIDITY_STATUS + +-- A test with curl would be : curl -X POST -d "28,48,2" 'http://192.168.1.17:8080/json.htm?type=command¶m=udevices&script=example.lua' + +-- This function split a string according to a defined separator +-- Entries are returned into an associative array with key values 1,2,3,4,5,6... +local function split(str, sep) + if sep == nil then + sep = "%s" + end + local t={} ; i=1 + local regex = string.format("([^%s]+)", sep) + for str in str:gmatch(regex) do + t[i] = str + i = i + 1 + end + return t +end + +-- Retrieve the request content +s = request['content']; + +-- Split the content into an array of values +local values = split(s, ","); + +-- Update some devices (index are here for this example) +domoticz_updateDevice(19,'',values[1]) +domoticz_updateDevice(20,values[2],values[2] .. ";" .. values[3]) diff --git a/lua_parsers/example_json.lua b/lua_parsers/example_json.lua new file mode 100644 index 0000000..00e4613 --- /dev/null +++ b/lua_parsers/example_json.lua @@ -0,0 +1,17 @@ +-- Example of JSON parser handling data with the following structure +--{ +-- "id": 13, +-- "name": "outside", +-- "temperature": 12.50, +-- "tags": ["France", "winter"] +--} + +-- A test with curl would be : curl -X POST -d "@test.json" 'http://192.168.1.17:8080/json.htm?type=command¶m=udevices&script=example_json.lua' + +-- Retrieve the request content +s = request['content']; + +-- Update some devices (index are here for this example) +local id = domoticz_applyJsonPath(s,'.id') +local s = domoticz_applyJsonPath(s,'.temperature') +domoticz_updateDevice(id,'',s) diff --git a/lua_parsers/example_owm.lua b/lua_parsers/example_owm.lua new file mode 100644 index 0000000..4b0a096 --- /dev/null +++ b/lua_parsers/example_owm.lua @@ -0,0 +1,34 @@ +-- Example of XML parser handling data with the following structure + +-- Data are coming from the OpenWeatherMap API : See http://www.openweathermap.org/current + +-- +-- +-- +-- FR +-- +-- +-- +-- +-- +-- +-- +-- +-- +-- +-- +-- +-- +-- +-- +-- + +-- Retrieve the request content +s = request['content']; + +-- Update some devices (index are here for this example) + +local temp = domoticz_applyXPath(s,'//current/temperature/@value') +local humidity = domoticz_applyXPath(s,'//current/humidity/@value') +local pressure = domoticz_applyXPath(s,'//current/pressure/@value') +domoticz_updateDevice(2988507,'',temp .. ";" .. humidity .. ";0;" .. pressure .. ";0") diff --git a/lua_parsers/example_xml.lua b/lua_parsers/example_xml.lua new file mode 100644 index 0000000..4491a74 --- /dev/null +++ b/lua_parsers/example_xml.lua @@ -0,0 +1,18 @@ +-- Example of XML parser handling data with the following structure +-- +-- +-- 13 +-- 29.99 +-- + +--} + +-- A test with curl would be : curl -X POST -d "@test.xml" 'http://192.168.1.17:8080/json.htm?type=command¶m=udevices&script=example_xml.lua' + +-- Retrieve the request content +s = request['content']; + +-- Update some devices (index are here for this example) +local id = domoticz_applyXPath(s,'//id/text()') +local s = domoticz_applyXPath(s,'//value/text()') +domoticz_updateDevice(id,'',s) diff --git a/lum.py b/lum.py new file mode 100644 index 0000000..f4e74ac --- /dev/null +++ b/lum.py @@ -0,0 +1,17 @@ +import os, sys +import requests +from subprocess import Popen, PIPE + +process = Popen(['wget','-O','/tmp/shot'+'foscam'+'.jpg','http://cam.home/media/?action=snapshot&user=admin&pwd=setaou'], stdout=PIPE) +(output, err) = process.communicate() +exit_code = process.wait() +process = Popen(["convert /tmp/shot"+'foscam'+".jpg -colorspace hsb -resize 1x1 txt: | grep \",*%)\" | cut -f 6 -d ',' | awk -F% '{print $1}'"], stdout=PIPE, shell=True) +(output, err) = process.communicate() +exit_code = process.wait() +print process +value = str(output).replace('\n','') +print value +url = 'http://localhost:81/json.htm?type=command¶m=udevice&idx=653&nvalue=0&svalue=' + value +r = requests.get(url) +print url +print r diff --git a/motionOff.sh b/motionOff.sh new file mode 100755 index 0000000..bba0670 --- /dev/null +++ b/motionOff.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +#kill `ps ax|grep motion |grep -v grep | cut -c 1-6` >/dev/null 2>/dev/null + +#kill `cat /home/pi/motion/motion.pid 2>/dev/null` >/dev/null 2>/dev/null + +#service motion stop >/dev/null 2>/dev/null + +#killall motion >/dev/null 2>/dev/null + + +#service motion stop diff --git a/motionOn.sh b/motionOn.sh new file mode 100755 index 0000000..927dc8a --- /dev/null +++ b/motionOn.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +#/home/pi/motion/motion.pid +#kill `ps ax|grep motion |grep -v grep | cut -c 1-6` >/dev/null 2>/dev/null + +#kill `cat /home/pi/motion/motion.pid 2>/dev/null` >/dev/null 2>/dev/null + +#sleep 1 + +#motion + +#service motion stop +#service motion start + +#touch /home/pi/motion/detection.old diff --git a/mplayer.sh b/mplayer.sh new file mode 100755 index 0000000..5a93b57 --- /dev/null +++ b/mplayer.sh @@ -0,0 +1,8 @@ +#!/bin/sh +runplayer=true +killall mplayer +while $runplayer + #do mplayer -really-quiet -msglevel all=-1 -ao pulse "http://192.168.1.3:8000/" > /dev/null 2>&1 + do mplayer -ao pulse "http://localhost:8000/" > /dev/null 2>&1 + sleep 10 +done diff --git a/mplayerOff.sh b/mplayerOff.sh new file mode 100755 index 0000000..4797410 --- /dev/null +++ b/mplayerOff.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +mpc stop; +mpc clear; +service mplayerd stop +killall mplayer + +#kill `ps ax |grep ssh |grep 6600 |cut -c 1-6` diff --git a/mplayerOn.sh b/mplayerOn.sh new file mode 100755 index 0000000..8ab7f3e --- /dev/null +++ b/mplayerOn.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +#Creation du pont ssh avec volumio +#ssh -N -L6600:127.0.0.1:6600 pi:raspberry@192.168.0.4 & +service mplayerd stop + +#Demarrage de la musique avant de redemarrer le client +#mpc clear;mpc load DiversRock;mpc play +mpc random off;mpc clear;mpc listall | shuf -n 10 |mpc add; mpc play + + +service mplayerd start diff --git a/nohup.out b/nohup.out new file mode 100644 index 0000000..fe1a736 --- /dev/null +++ b/nohup.out @@ -0,0 +1,8 @@ +AkhenatonSDA12020-14.img +./saveAkhenaton.sh: ligne 4: /media/ImagesAkhenaton/AkhenatonSDA1$(date '+%Y-%W').img.gz: Aucun fichier ou dossier de ce type +AkhenatonSDA12020-14.img +./saveAkhenaton.sh: ligne 4: /media/ImagesAkhenaton/AkhenatonSDA1$(date '+%Y-%W').img.gz: Aucun fichier ou dossier de ce type +AkhenatonSDA12020-14.img +129796096+0 enregistrements lus +129796096+0 enregistrements écrits +66455601152 bytes (66 GB, 62 GiB) copied, 2738,94 s, 24,3 MB/s diff --git a/octoprint2Status.sh b/octoprint2Status.sh new file mode 100755 index 0000000..262209c --- /dev/null +++ b/octoprint2Status.sh @@ -0,0 +1,16 @@ +#!/bin/bash +DOMO_IP="localhost" # Domoticz IP Address +DOMO_PORT="81" # Domoticz Port +OCTOPRINT_IDX=682 # numéro ID de l interrupteur du relais + +json="http://akhenaton-3:5002/api/job?apikey=A6C678D49AC8465AB0AF01EBBF2C754F" +echo "$json" +reponse=`curl -i -H -s "Accept: application/json" $json|grep "state"|awk -F: '{print $2}'` +echo "$reponse" + +if [ "$reponse" = " \"Operational\"" ] +then + sleep 120 + curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$OCTOPRINT_IDX&switchcmd=Off" +fi + diff --git a/octoprintCallApi.sh b/octoprintCallApi.sh new file mode 100755 index 0000000..0eac5d5 --- /dev/null +++ b/octoprintCallApi.sh @@ -0,0 +1,17 @@ +#!/bin/bash +DOMO_IP="localhost" # Domoticz IP Address +DOMO_PORT="81" # Domoticz Port +OCTOPRINT_IDX=683 # numéro ID de l interrupteur du relais + +json="http://akhenaton-3:5000/api/job?apikey=B5746ACFF37140D0B5F6FEAAC4413B5C" +echo "$json" +reponse=`curl -s "Accept: application/json" $json|sed -e 's/[{}]/''/g' |awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'|grep "state"|awk -F: '{print $2}'` +echo "$reponse" + +if [ "$reponse" = "\"Operational\"" ] +then + echo "On eteint tout" + sleep 120 + curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$OCTOPRINT_IDX&switchcmd=Off" +fi + diff --git a/octoprintStatus.sh b/octoprintStatus.sh new file mode 100755 index 0000000..1acb2d6 --- /dev/null +++ b/octoprintStatus.sh @@ -0,0 +1,18 @@ +#!/bin/bash +DOMO_IP="localhost" # Domoticz IP Address +DOMO_PORT="81" # Domoticz Port +OCTOPRINT_IDX=683 # numéro ID de l interrupteur du relais + +json="http://akhenaton-3:5000/api/job?apikey=B5746ACFF37140D0B5F6FEAAC4413B5C" +echo "$json" +reponse=`curl -s "Accept: application/json" $json|sed -e 's/[{}]/''/g' |awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'|grep "state"|awk -F: '{print $2}'` +echo "$reponse" + +if [ "$reponse" = "\"Operational\"" ] +then + echo "On eteint tout" + sleep 120 + curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$OCTOPRINT_IDX&switchcmd=Off" + service motion stop +fi + diff --git a/on_event_end.sh b/on_event_end.sh new file mode 100755 index 0000000..e88b09d --- /dev/null +++ b/on_event_end.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +echo "Fin event" >>/home/souti/motion/detection.log + + +json="http://localhost:81/json.htm?type=command¶m=udevice&idx=240&nvalue=0" +curl -s -i -H "Accept: application/json" $json >/dev/null + +#presence=`curl "http://localhost:81/json.htm?type=devices&rid=183" 2>/dev/null|grep Status|grep "On"` + +echo "Fin event envoi de mail $presence" >>/home/souti/motion/detection.log +echo "Detection de mouvement en absence " |mail -a `ls -rt /home/souti/motion/*avi | tail -1` -r souti@free.fr -s "Detection de mouvement" -- jerome.delacotte@gmail.com + + +#if [ "$presence" = "" ]; then +# echo "Fin event envoi de mail $presence" >>/home/souti/motion/detection.log +# echo "Detection de mouvement en absence " |mail -a `ls -rt /home/souti/motion/*avi | tail -1` -r souti@free.fr -s "Detection de mouvement" -- jerome.delacotte@gmail.com +#else +# echo "Fin event Pas d'envoi de mail $presence" >>/home/souti/motion/detection.log +#fi diff --git a/on_event_start.sh b/on_event_start.sh new file mode 100755 index 0000000..90bbb9d --- /dev/null +++ b/on_event_start.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +echo "Debut event" >>/home/pi/motion/detection.log + + +json="http://localhost:81/json.htm?type=command¶m=udevice&idx=240&nvalue=1" +curl -s -i -H "Accept: application/json" $json >/dev/null + diff --git a/on_motion_detected.sh b/on_motion_detected.sh new file mode 100755 index 0000000..1c55345 --- /dev/null +++ b/on_motion_detected.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +echo "Detection motion" >>/home/pi/motion/detection.log diff --git a/perf.sh b/perf.sh new file mode 100755 index 0000000..7a46c7d --- /dev/null +++ b/perf.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +while : +do +ps aux --sort=-%cpu | grep -v "watch" |awk -v date="$(date +%Y-%m-%d-"%H:%M:%S")" 'NR>1{if($3>30.0) if($10>"0:10")print date,$10,$2,$3,$11}' >>/tmp/perf.txt +sleep 10 +done diff --git a/power.sh b/power.sh new file mode 100755 index 0000000..d36ea04 --- /dev/null +++ b/power.sh @@ -0,0 +1,6 @@ +#!/bin/bash +#sudo apt install tlp tlp-rdw +# sudo tlp-stat -b +# upower -i `upower -e | grep 'BAT'` +# upower -i `upower -e | grep 'BAT'`|grep "energy-rate:" + upower -i `upower -e | grep 'BAT'`|grep "energy-rate:"|awk -F: '{print $2}'|awk -F" " '{print $1}' diff --git a/prestashop.sh b/prestashop.sh new file mode 100755 index 0000000..919e3ea --- /dev/null +++ b/prestashop.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +cd /media/WDBlue/backup/prestashop/daily/; +/usr/bin/mysqldump --databases prestashop > /tmp/prestashop.sql; +/bin/tar cvzf prestashop"$(date '+%Y-%m-%d')".tgz /tmp/prestashop.sql +/bin/tar cvzf prestashopSiteWeb"$(date '+%Y-%m-%d')".tgz /opt/prestashop/* + diff --git a/prestashopHourly.sh b/prestashopHourly.sh new file mode 100755 index 0000000..9521df9 --- /dev/null +++ b/prestashopHourly.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +cd /media/WDBlue/backup/prestashop/hourly/; +/usr/bin/mysqldump --databases prestashop > /tmp/prestashop.sql; +/bin/tar cvzf prestashop"$(date '+%H')".tgz /tmp/prestashop.sql +/bin/tar cvzf prestashopSiteWeb"$(date '+%H')".tgz /opt/prestashop/* + diff --git a/python/.AppleDouble/.Parent b/python/.AppleDouble/.Parent new file mode 100644 index 0000000..8c2568b Binary files /dev/null and b/python/.AppleDouble/.Parent differ diff --git a/python/.AppleDouble/domoticz.py b/python/.AppleDouble/domoticz.py new file mode 100644 index 0000000..fe51d55 Binary files /dev/null and b/python/.AppleDouble/domoticz.py differ diff --git a/python/.AppleDouble/googlepubsub.py b/python/.AppleDouble/googlepubsub.py new file mode 100644 index 0000000..cb77ba5 Binary files /dev/null and b/python/.AppleDouble/googlepubsub.py differ diff --git a/python/.AppleDouble/reloader.py b/python/.AppleDouble/reloader.py new file mode 100644 index 0000000..fc7f915 Binary files /dev/null and b/python/.AppleDouble/reloader.py differ diff --git a/python/.AppleDouble/script_device_PIRsmarter.py b/python/.AppleDouble/script_device_PIRsmarter.py new file mode 100644 index 0000000..650d3b1 Binary files /dev/null and b/python/.AppleDouble/script_device_PIRsmarter.py differ diff --git a/python/domoticz.py b/python/domoticz.py new file mode 100644 index 0000000..8a68384 --- /dev/null +++ b/python/domoticz.py @@ -0,0 +1,158 @@ +""" +Helper module for python+domoticz +Every script_device_*.py script has the following variables + * changed_device: the current device that changed (object of Device) + * changed_device_name: name of current device (same as changed_device.name) + * is_daytime: boolean, true when it is is daytime + * is_nighttime: same for the night + * sunrise_in_minutes: integer + * sunset_in_minutes: integer + * user_variables: dictionary from string to value + +For more advanced project, you may want to use modules. +say you have a file heating.py +You can do +import heating +heating.check_heating() + +But heating has a different scope, and won't have access to these variables. +By importing this module, you can have access to them in a standard way +import domoticz +domoticz.changed_device + +And you also have access to more: + * same as in the device scripts (changed_device ... user_variables) + * devices: dictionary from string to Device + + +""" +#try: +import DomoticzEvents as domoticz_ # +#except: +# pass + +import reloader +import datetime +import re + +# Enable plugins to do: +# from Domoticz import Devices, Images, Parameters, Settings +try: + Devices +except NameError: + Devices = {} + domoticz_.Log(1, "Devices was not created by Domoticz C++ code") + +try: + Images +except NameError: + Images = {} + domoticz_.Log(1, "Images was not created by Domoticz C++ code") + +try: + Parameters +except NameError: + Parameters = {} + domoticz_.Log(1, "Parameters was not created by Domoticz C++ code") + +try: + Settings +except NameError: + Settings = {} + domoticz_.Log(1, "Settings was not created by Domoticz C++ code") + +#def _log(type, text): # 'virtual' function, will be modified to call +# pass + +def log(*args): + domoticz_.Log(0, " ".join([str(k) for k in args])) + +def error(*args): + domoticz_.Log(1, " ".join([str(k) for k in args])) + +reloader.auto_reload(__name__) + +# this will be filled in by the c++ part +devices = {} +device = None + + +testing = False +commands = [] + +event_system = None # will be filled in by domoticz +def command(name, action, file): + if testing: + commands.append((name, action)) + else: + event_system.command(name, action, file) + +def process_commands(): + for name, action in commands: + device = devices[name] + if action == "On": + device.n_value = 1 + print ("\tsetting %s On" % name) + elif action == "Off": + device.n_value = 0 + print ("\tsetting %s On" % name) + else: + print ("unknown command", name, action) + del commands[:] + +class Device(object): + def __init__(self, id, name, type, sub_type, switch_type, n_value, n_value_string, s_value, last_update): + devices[name] = self + self.id = id + self.name = name + self.type = type + self.sub_type = sub_type + self.switch_type = switch_type + self.n_value = n_value + self.n_value_string = n_value_string + self.s_value = s_value + self.last_update_string = last_update + # from http://stackoverflow.com/questions/127803/how-to-parse-iso-formatted-date-in-python + if self.last_update_string: + # from http://stackoverflow.com/questions/127803/how-to-parse-iso-formatted-date-in-python + try: + self.last_update = datetime.datetime(*map(int, re.split('[^\d]', self.last_update_string)[:])) + if str(self.last_update_string) != str(self.last_update): + log("Error parsing date:", self.last_update_string, " parsed as", str(self.last_update)) + except: + log("Exception while parsing date:", self.last_update_string) + else: + self.last_update = None + + def __str__(self): + return "Device(%s, %s, %s, %s)" % (self.id, self.name, self.n_value, self.s_value) + def __repr__(self): + return "Device(%s, %s, %s, %s)" % (self.id, self.name, self.n_value, self.s_value) + + def last_update_was_ago(self, **kwargs): + """Arguments can be: days[, seconds[, microseconds[, milliseconds[, minutes[, hours[, weeks]""" + return self.last_update + datetime.deltatime(**kwargs) < datetime.datetime.now() + + def is_on(self): + return self.n_value == 1 + + def is_off(self): + return self.n_value == 0 + + def on(self, after=None, reflect=False): + if self.is_off() or after is not None: + self._command("On" , after=after) + if reflect: + self.n_value = 1 + + def off(self, after=None, reflect=False): + if self.is_on() or after is not None: + self._command("Off" , after=after) + if reflect: + self.n_value = 0 + + def _command(self, action, after=None): + if after is not None: + command(self.name, "%s AFTER %d" % (action, after), __file__) + else: + command(self.name, action, __file__) diff --git a/python/domoticz.pyc b/python/domoticz.pyc new file mode 100644 index 0000000..4ade9f3 Binary files /dev/null and b/python/domoticz.pyc differ diff --git a/python/googlepubsub.py b/python/googlepubsub.py new file mode 100644 index 0000000..f58608e --- /dev/null +++ b/python/googlepubsub.py @@ -0,0 +1,56 @@ +import httplib2 +import argparse +import base64 +import csv +import datetime +import random +import sys +import time +import base64 +import domoticz + +# This script connects Domoticz with Google Cloud PubSub API +# To make it works : +# 1 - Install the Google API Client Python Library : pip install --upgrade google-api-python-client (or see https://cloud.google.com/pubsub/libraries) +# 2 - Activate the Google Cloud PubSub API in the Google Cloud Console +# 3 - Generate a Service account key in the Google Cloud Console and download the private key in JSON format +# 4 - Transfer the json key into the domoticz install dir +# 5 - Set the ENV variable GOOGLE_APPLICATION_CREDENTIALS to the path of your Service account key +# 6 - Create a topic in the "PubSub" Google Cloud Console +# 7 - Modify the variable PUBSUB_TOPICNAME below with the topic name + +# Required library to make pubsub google api working fine +from apiclient import discovery +from oauth2client import client as oauth2client + +# Required privileges +PUBSUB_SCOPES = ['https://www.googleapis.com/auth/pubsub'] + +# Topic name defined in the Google Cloud PubSub Console +PUBSUB_TOPICNAME = 'projects/affable-enigma-136123/topics/domoticz' + +def create_pubsub_client(http=None): + credentials = oauth2client.GoogleCredentials.get_application_default() + if credentials.create_scoped_required(): + credentials = credentials.create_scoped(PUBSUB_SCOPES) + if not http: + http = httplib2.Http() + credentials.authorize(http) + + return discovery.build('pubsub', 'v1', http=http) + +def publish_message(client,topicname,message): + message1 = base64.b64encode(message) + body = { + 'messages': [ + {'data': message1} + ] + } + resp = client.projects().topics().publish(topic=topicname, body=body).execute() + +def main(argv): + client = create_pubsub_client() + publish_message(client,PUBSUB_TOPICNAME,data) # noqa: F821 + +if __name__ == '__main__': + main(sys.argv) diff --git a/python/reloader.py b/python/reloader.py new file mode 100644 index 0000000..7869e1a --- /dev/null +++ b/python/reloader.py @@ -0,0 +1,43 @@ +""" +Python only loads modules once, so domoticz will only load a module the first time it is needed. Code changes will not be reflected, only after a restart of domoticz. Note that doesn't hold for scripts, they always get reloaded. +To have your module reloaded, you can enter the following code in it. +import reloader +reloader.auto_reload(__name__) +""" + +import sys +import os + +try: + reload # Python 2 +except NameError: + from importlib import reload # Python 3 + + +# mark module as a module to reload +def auto_reload(module_name): + import domoticz as dz + path = _py_source(sys.modules[module_name]) + _module_mtimes[module_name] = os.path.getmtime(path) + + +# below this is internal stuff + +# maps from module name to modification time (mtime) +_module_mtimes = {} + +# convert module to python source filename +def _py_source(module): + path = module.__file__ + if path[:-1].endswith("py"): + path = path[:-1] + return path + +def _check_reload(): + for module_name, loaded_mtime in _module_mtimes.items(): + path = _py_source(sys.modules[module_name]) + # if file is changed, the current mtime is greater + if loaded_mtime < os.path.getmtime(path): + reload(sys.modules[module_name]) # and reload + else: + pass diff --git a/python/reloader.pyc b/python/reloader.pyc new file mode 100644 index 0000000..d5b1ea2 Binary files /dev/null and b/python/reloader.pyc differ diff --git a/python/script_device_demo.py b/python/script_device_demo.py new file mode 100644 index 0000000..02d6d6f --- /dev/null +++ b/python/script_device_demo.py @@ -0,0 +1,18 @@ +import DomoticzEvents as DE + +DE.Log("Python: Changed: " + DE.changed_device.Describe()) + +if DE.changed_device_name == "Test": + if DE.Devices["Test_Target"].n_value_string == "On": + DE.Command("Test_Target", "Off") + + if DE.Devices["Test_Target"].n_value_string == "Off": + DE.Command("Test_Target", "On") + +DE.Log("Python: Number of user_variables: " + str(len(DE.user_variables))) + +# All user_variables are treated as strings, convert as necessary +for key, value in DE.user_variables.items(): + DE.Log("Python: User-variable '{0}' has value: {1}".format(key, value)) + +# Description of Device_object should go here... diff --git a/python/script_time_demo.py b/python/script_time_demo.py new file mode 100644 index 0000000..7da52fe --- /dev/null +++ b/python/script_time_demo.py @@ -0,0 +1,11 @@ +import DomoticzEvents as DE + +if DE.is_daytime: + DE.Log("Python: It's daytime!") + +if DE.is_nighttime: + DE.Log("Python: It's nighttime!") + +DE.Log("Python: Sunrise in minutes: " + str(DE.sunrise_in_minutes)) +DE.Log("Python: Sunset in minutes: " + str(DE.sunset_in_minutes)) +DE.Log("Python: Minutes since midnight: " + str(DE.minutes_since_midnight)) diff --git a/pzem.sh b/pzem.sh new file mode 100755 index 0000000..16beefc --- /dev/null +++ b/pzem.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +round() { + printf "%.${2}f" "${1}" +} + +# Effectuer la requête HTTP et stocker la réponse JSON dans une variable +response=$(curl -s http://192.168.1.42/getData) + +response2=$(curl -s "http://192.168.1.40/getData") +#response2=$(curl -s "http://192.168.1.3:81/json.htm?type=devices&rid=1188") +echo $response2 + +# Vérifier si la requête a réussi (status code 200) +if [ $? -eq 0 ]; then + # Extraire la valeur de "power" à l'aide de jq + powerValue=$(echo "$response" | jq -r '.power') + st=$(echo "$response2" | jq -r '.PIN_INJECTION') + #st=$(echo "$response2" | jq -r '.result[0].Data') + echo $st + + # Vérifier si la valeur de "power" est non nulle + if [ "$powerValue" != "null" ]; then + echo "Valeur de power : $powerValue" + + # Vérifier si la valeur est inférieure à 10 + if (( $(echo "$powerValue < 10" | bc -l) )); then + echo "La valeur de power est inférieure à 10." + # response=$(curl -s http://192.168.1.40/stopInjection) + fi + + + idx="1191" + if [ "$st" == "0" ]; then + url="http://192.168.1.3:81/json.htm?type=command¶m=udevice&idx=$idx&svalue=0;0&nvalue=0" + curl -X GET "$url" + # powerValue=$powerValue + idx="1194" + url="http://192.168.1.3:81/json.htm?type=command¶m=udevice&idx=$idx&svalue=$powerValue;0&nvalue=0" + curl -X GET "$url" + else + url="http://192.168.1.3:81/json.htm?type=command¶m=udevice&idx=$idx&svalue=$powerValue;0&nvalue=0" + curl -X GET "$url" + # powerValue=$powerValue + idx="1194" + url="http://192.168.1.3:81/json.htm?type=command¶m=udevice&idx=$idx&svalue=0;0&nvalue=0" + curl -X GET "$url" + + fi + + + else + echo "La clé 'power' n'existe pas dans le JSON." + fi +else + echo "Erreur lors de la requête HTTP." +fi + diff --git a/qualiteAir.php b/qualiteAir.php new file mode 100755 index 0000000..224bb16 --- /dev/null +++ b/qualiteAir.php @@ -0,0 +1,395 @@ +#https://easydomoticz.com/forum/viewtopic.php?f=17&t=3366 +_isStation = true; +$class->_inseeCode = "35238"; +$class->_stationCode = "19002"; +$class->_long = "-2.1333"; +$class->_lat = "47.7333"; + +#echo "\n Station: ".$class->getStationCode("Rennes"); +#echo "\n Insee: ".$class->getInseeCode("Rennes")."\n"; + + +echo "\n Station: ".$class->getCoStation(); +echo "\n CO: ".$class->getCo(); +echo "\n Max: ".$class->getCoMax(); +echo "\n Station: ".$class->getNo2Station(); +echo "\n NO2: ".$class->getNo2(); +echo "\n Max: ".$class->getNo2Max(); +echo "\n Station: ".$class->getSo2Station(); +echo "\n SO2: ".$class->getSo2(); +echo "\n Max: ".$class->getSo2Max(); +echo "\n Station: ".$class->getO3Station(); +echo "\n O3: ".$class->getO3(); +echo "\n Max: ".$class->getO3Max(); +echo "\n Station: ".$class->getPm10Station(); +echo "\n PM10: ".$class->getPm10(); +echo "\n Max: ".$class->getPm10Max(); +echo "\n Station: ".$class->getPm25Station(); +echo "\n PM2.5: ".$class->getPm25(); +echo "\n Max: ".$class->getPm25Max(); +echo "\n Station: ".$class->getAtmoIndiceStation(); +echo "\n Atmo: ".$class->getAtmoIndice(); +echo "\n -NO2: ".$class->getAtmoNo2Indice(); +echo "\n -SO2: ".$class->getAtmoSo2Indice(); +echo "\n -O3: ".$class->getAtmoO3Indice(); +echo "\n -PM10: ".$class->getAtmoPm10Indice(); +echo "\n -Comment: ".$class->getAtmoIndiceComment(); +echo "\n -in 1 day: ".$class->getAtmoTomorrowIndice(); +echo "\n -in 2 days: ".$class->getAtmo2DayIndice(); + +echo "\n Station: ".$class->getStationCode("yourCity"); +echo "\n Insee: ".$class->getInseeCode("yourCity")."\n"; + +#Ozone +file_get_contents("http://localhost:81/json.htm?type=command¶m=udevice&idx=90&nvalue=".$class->getAtmoO3Indice()); +file_get_contents("http://localhost:81/json.htm?type=command¶m=udevice&idx=93&nvalue=".$class->getAtmoPm10Indice()); +file_get_contents("http://localhost:81/json.htm?type=command¶m=udevice&idx=92&nvalue=".$class->getAtmoSo2Indice()); +file_get_contents("http://localhost:81/json.htm?type=command¶m=udevice&idx=91&nvalue=".$class->getAtmoNo2Indice()); + +class prevair +{ + private $_base_url = "http://www2.prevair.org/ineris-web-services.php?url=mesureJourna&date="; + private $_url_station = "http://www2.prevair.org/ineris-web-services.php?url=stations&date="; + private $_atmo_url = "http://www2.prevair.org/ineris-web-services.php?url=atmo&date="; + private $_atmo_data; + private $_date; + + public $_isStation = false; + public $_inseeCode; + public $_stationCode; + public $_long; + public $_lat; + + + public function __construct() + { + $this->_date = date("Y-m-d"); + $this->_base_url = $this->_base_url.$this->_date."&code_polluant="; + $this->_atmo_data = json_decode(file_get_contents($this->_atmo_url.$this->_date),true); + } + + private function getDistance($lat1, $lng1, $lat2, $lng2) { + $earth_radius = 6378137; + $rlo1 = deg2rad($lng1); + $rla1 = deg2rad($lat1); + $rlo2 = deg2rad($lng2); + $rla2 = deg2rad($lat2); + $dlo = ($rlo2 - $rlo1) / 2; + $dla = ($rla2 - $rla1) / 2; + $a = (sin($dla) * sin($dla)) + cos($rla1) * cos($rla2) * (sin($dlo) * sin($dlo)); + $d = 2 * atan2(sqrt($a), sqrt(1 - $a)); + return round(($earth_radius * $d)/1000); + } + + private function findDataId($data,$isAtmo = false) + { + $i = 1; + $distMin = 2000000; + $minId = 0; + $arrLen = count($data); + + if($isAtmo == true) + { + $longIndice = 2; + $latIndice = 3; + } + else + { + $longIndice = 2; + $latIndice = 1; + } + + if($this->_isStation != false) + { + while($i != $arrLen) + { + if($isAtmo != false) + { + if($data[$i][1] == $this->_inseeCode) + { + $minId = $i; + break; + } + } + else + { + if($data[$i][0] == $this->_stationCode) + { + $minId = $i; + break; + } + } + $i++; + } + } + else + { + while($i != $arrLen) + { + $distance = $this->getDistance($this->_lat, $this->_long, $data[$i][$latIndice], $data[$i][$longIndice]); + if($distMin > $distance) + { + $distMin = $distance; + $minId = $i; + } + $i++; + } + } + return $minId; + } + + public function getStationName($long,$lat) + { + $data = file_get_contents($this->_url_station.$this->_date); + $data = json_decode($data,true); + $len = count($data); + $i = 0; + $name = false; + while($i != $len) + { + if($data[$i][5] == $lat && $data[$i][6] == $long) + { + $name = $data[$i][1]; + break; + } + $i++; + } + return $data[$i][2]." - ".$data[$i][4]; + } + + public function getStationCode($city) + { + $code = ""; + $data = file_get_contents($this->_url_station.$this->_date); + $data = json_decode($data,true); + $len = count($data); + $i = 0; + $long = false; + $lat = false; + while($i != $len) + { + if(strcasecmp($data[$i][4],$city) == 0) + { + $code = $data[$i][0]; + break; + } + $i++; + } + return $code; + } + + public function getInseeCode($city) + { + $code = ""; + $data = file_get_contents($this->_url_station.$this->_date); + $data = json_decode($data,true); + $len = count($data); + $i = 0; + $long = false; + $lat = false; + while($i != $len) + { + if(strcasecmp($data[$i][4],$city) == 0) + { + $code = $data[$i][3]; + break; + } + $i++; + } + return $code; + } + + public function getNo2() + { + $data = json_decode(file_get_contents($this->_base_url."03"),true); + $id = $this->findDataId($data); + return $data[$id][6]; + } + + public function getSo2() + { + $data = json_decode(file_get_contents($this->_base_url."01"),true); + $id = $this->findDataId($data); + return $data[$id][6]; + } + + public function getO3() + { + $data = json_decode(file_get_contents($this->_base_url."08"),true); + $id = $this->findDataId($data); + return $data[$id][6]; + } + + public function getPm10() + { + $data = json_decode(file_get_contents($this->_base_url."24"),true); + $id = $this->findDataId($data); + return $data[$id][6]; + } + + public function getPm25() + { + $data = json_decode(file_get_contents($this->_base_url."39"),true); + $id = $this->findDataId($data); + return $data[$id][6]; + } + + public function getCo() + { + $data = json_decode(file_get_contents($this->_base_url."04"),true); + $id = $this->findDataId($data); + return $data[$id][6]; + } + + public function getNo2Max() + { + $data = json_decode(file_get_contents($this->_base_url."03"),true); + $id = $this->findDataId($data); + return $data[$id][5]; + } + + public function getSo2Max() + { + $data = json_decode(file_get_contents($this->_base_url."01"),true); + $id = $this->findDataId($data); + return $data[$id][5]; + } + + public function getO3Max() + { + $data = json_decode(file_get_contents($this->_base_url."08"),true); + $id = $this->findDataId($data); + return $data[$id][5]; + } + + public function getPm10Max() + { + $data = json_decode(file_get_contents($this->_base_url."24"),true); + $id = $this->findDataId($data); + return $data[$id][5]; + } + + public function getPm25Max() + { + $data = json_decode(file_get_contents($this->_base_url."39"),true); + $id = $this->findDataId($data); + return $data[$id][5]; + } + + public function getCoMax() + { + $data = json_decode(file_get_contents($this->_base_url."04"),true); + $id = $this->findDataId($data); + return $data[$id][5]; + } + + public function getNo2Station() + { + $data = json_decode(file_get_contents($this->_base_url."03"),true); + $id = $this->findDataId($data); + return $this->getStationName($data[$id][2],$data[$id][1]); + } + + public function getSo2Station() + { + $data = json_decode(file_get_contents($this->_base_url."01"),true); + $id = $this->findDataId($data); + return $this->getStationName($data[$id][2],$data[$id][1]); + } + + public function getO3Station() + { + $data = json_decode(file_get_contents($this->_base_url."08"),true); + $id = $this->findDataId($data); + return $this->getStationName($data[$id][2],$data[$id][1]); + } + + public function getPm10Station() + { + $data = json_decode(file_get_contents($this->_base_url."24"),true); + $id = $this->findDataId($data); + return $this->getStationName($data[$id][2],$data[$id][1]); + } + + public function getPm25Station() + { + $data = json_decode(file_get_contents($this->_base_url."39"),true); + $id = $this->findDataId($data); + return $this->getStationName($data[$id][2],$data[$id][1]); + } + + public function getCoStation() + { + $data = json_decode(file_get_contents($this->_base_url."04"),true); + $id = $this->findDataId($data); + return $this->getStationName($data[$id][2],$data[$id][1]); + } + + public function getAtmoIndice() + { + $id = $this->findDataId($this->_atmo_data,true); + return $this->_atmo_data[$id][7]; + } + + public function getAtmoSo2Indice() + { + $id = $this->findDataId($this->_atmo_data,true); + return $this->_atmo_data[$id][8]; + } + + public function getAtmoNo2Indice() + { + $id = $this->findDataId($this->_atmo_data,true); + return $this->_atmo_data[$id][9]; + } + + public function getAtmoO3Indice() + { + $id = $this->findDataId($this->_atmo_data,true); + return $this->_atmo_data[$id][10]; + } + + public function getAtmoPm10Indice() + { + $id = $this->findDataId($this->_atmo_data,true); + return $this->_atmo_data[$id][11]; + } + + public function getAtmoIndiceStation() + { + $id = $this->findDataId($this->_atmo_data,true); + return $this->_atmo_data[$id][4]." - ".$this->_atmo_data[$id][5]." - ".$this->_atmo_data[$id][6]." - ".$this->_atmo_data[$id][13]; + } + + public function getAtmoIndiceComment() + { + $id = $this->findDataId($this->_atmo_data,true); + return $this->_atmo_data[$id][12]; + } + + public function getAtmoTomorrowIndice() + { + $date = date("Y-m-d", strtotime("+1 day")); + $data = json_decode(file_get_contents($this->_atmo_url.$date),true); + $id = $this->findDataId($data,true); + return $data[$id][7]; + } + + public function getAtmo2DayIndice() + { + $date = date("Y-m-d", strtotime("+2 day")); + $data = json_decode(file_get_contents($this->_atmo_url.$date),true); + $id = $this->findDataId($data,true); + return $data[$id][7]; + } +} + +?> diff --git a/qualiteAir.pl b/qualiteAir.pl new file mode 100755 index 0000000..a01960d --- /dev/null +++ b/qualiteAir.pl @@ -0,0 +1,79 @@ +#https://easydomoticz.com/domoticz-integrer-les-donnees-qualite-de-lair-en-dehors-de-paris/ +#!/usr/bin/perl +use v5.14; +use LWP::Simple; # From CPAN +use XML::Simple; # From CPAN +use strict; # Good practice +use warnings; # Good practice +use utf8; +use POSIX; +use feature qw< unicode_strings >; +#Support: domoticz@e-nef.com ou forum Domoticz + +#Pour ajouter les librairies nécessaires: +#sudo apt-get install libjson-perl libdatetime-perl libwww-perl libxml-simple-perl + +#A adapter à votre configuration: +my $domo_ip="localhost"; +my $domo_port="81"; +my $agglomeration="NANTES"; +my $dz_ind=54; #ID d'un device virtuel de type CO2 pour tous les suivants +my $dz_o3=90; +my $dz_no2=91; +my $dz_so2=92; +my $dz_pm10=93; + +#Ne pas toucher en dessous +my $trendsurl = " http://www.lcsqa.org/surveillance/indices/prevus/jour/xml/"; +#my $trendsurl = " http://www.lcsqa.org/indices-qualite-air/liste/jour"; + +my $json = get( $trendsurl ); +die "Could not get $trendsurl!" unless defined $json; + +my $xml = new XML::Simple; +# Decode the entire JSON +my $decoded = $xml->XMLin( $json ); + +# you'll get this (it'll print out); comment this when done. +#print Dumper $decoded; + +foreach my $f ( @{$decoded->{node}} ) { + if ($f->{"agglomeration"}eq $agglomeration) { + print $f->{"valeurIndice"} . " " . $f->{"SousIndiceO3"} . " " . $f->{"SousIndiceNO2"} ." ". $f->{"SousIndiceSO2"} . " " .$f->{"SousIndicePM10"} . "\n"; + my $payload=$f->{"valeurIndice"}; + if (isdigit($payload)) { + `curl -s "http://$domo_ip:$domo_port/json.htm?type=command¶m=udevice&idx=$dz_ind&nvalue=$payload"`; } + else { + `curl -s "http://$domo_ip:$domo_port/json.htm?type=command¶m=udevice&idx=$dz_ind&nvalue=0"`; + } + $payload=$f->{"SousIndiceO3"}; + if (isdigit($payload)) { + `curl -s "http://$domo_ip:$domo_port/json.htm?type=command¶m=udevice&idx=$dz_o3&nvalue=$payload"`; + } + else { + `curl -s "http://$domo_ip:$domo_port/json.htm?type=command¶m=udevice&idx=$dz_o3&nvalue=0"`; + } + $payload=$f->{"SousIndiceNO2"}; + if (isdigit($payload)) { + `curl -s "http://$domo_ip:$domo_port/json.htm?type=command¶m=udevice&idx=$dz_no2&nvalue=$payload"`; + } + else { + `curl -s "http://$domo_ip:$domo_port/json.htm?type=command¶m=udevice&idx=$dz_no2&nvalue=0"`; + } + $payload=$f->{"SousIndiceSO2"}; + if (isdigit($payload)) { + `curl -s "http://$domo_ip:$domo_port/json.htm?type=command¶m=udevice&idx=$dz_so2&nvalue=$payload"`; + } + else { + `curl -s "http://$domo_ip:$domo_port/json.htm?type=command¶m=udevice&idx=$dz_so2&nvalue=0"`; + } + $payload=$f->{"SousIndicePM10"}; + if (isdigit($payload)) { + `curl -s "http://$domo_ip:$domo_port/json.htm?type=command¶m=udevice&idx=$dz_pm10&nvalue=$payload"`; + } + else { + `curl -s "http://$domo_ip:$domo_port/json.htm?type=command¶m=udevice&idx=$dz_pm10&nvalue=0"`; + } + } +} + diff --git a/radars.sh b/radars.sh new file mode 100755 index 0000000..555525b --- /dev/null +++ b/radars.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +value=`/usr/bin/lynx --dump http://www.radars-mobiles.fr/dept/56-morbihan/ |grep -v http|grep emplacement |grep -yE "ploermel|glenac|gacilly|ruffiac|missiriac|monterrein|caro|nicolas"|awk -F"-" '{print $1}'` + + + +if [ -n "$value" ]; +then +echo $value + echo $value | /usr/bin/mutt -s "Radars presents sur trajet " jerome.delacotte@gmail.com +fi + diff --git a/radio.sh b/radio.sh new file mode 100755 index 0000000..f48258e --- /dev/null +++ b/radio.sh @@ -0,0 +1,9 @@ +#!/bin/bash + + +#while true : +#do +sleep 2 +mplayer -ao alsa -playlist http://volumio:8000/mpd.m3u 2>/dev/null >/dev/null +#sleep 5 +#done diff --git a/radio2.sh b/radio2.sh new file mode 100755 index 0000000..f48258e --- /dev/null +++ b/radio2.sh @@ -0,0 +1,9 @@ +#!/bin/bash + + +#while true : +#do +sleep 2 +mplayer -ao alsa -playlist http://volumio:8000/mpd.m3u 2>/dev/null >/dev/null +#sleep 5 +#done diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..a302be9 --- /dev/null +++ b/readme.txt @@ -0,0 +1,5 @@ +Place your scripts you want to be executed by domoticz in here. + +Special scripts: +domoticz_main (on windows domoticz_main.bat), will be executed when a switch is pressed (On/Off) +to use this script, remove the underscore in front of the filename diff --git a/restart_domoticz b/restart_domoticz new file mode 100755 index 0000000..ecab0aa --- /dev/null +++ b/restart_domoticz @@ -0,0 +1,6 @@ +#!/bin/sh + +sudo service domoticz.sh stop +echo "please standby... (waiting 8 seconds)" +sleep 8 +sudo service domoticz.sh start diff --git a/saveAkhenaton.sh b/saveAkhenaton.sh new file mode 100755 index 0000000..edd3949 --- /dev/null +++ b/saveAkhenaton.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +echo AkhenatonSDA1"$(date '+%Y-%W')".img +nice -n 19 dd if=/dev/sda7 |gzip >/media/MEMUP/ImagesAkhenaton/AkhenatonSDA7"$(date '+%Y-%W')".img.gz diff --git a/sonoSDB.sh b/sonoSDB.sh new file mode 100755 index 0000000..efd9790 --- /dev/null +++ b/sonoSDB.sh @@ -0,0 +1,5 @@ +#!/bin/bash + + +ssh pi@192.168.0.44 "/home/pi/script/enableMode.sh 3" >/dev/null 2>/dev/null + diff --git a/sonoSalon.sh b/sonoSalon.sh new file mode 100755 index 0000000..4e47dc5 --- /dev/null +++ b/sonoSalon.sh @@ -0,0 +1,6 @@ +#!/bin/bash + + +ssh pi@192.168.0.44 "/home/pi/script/enableMode.sh 3" >/dev/null 2>/dev/null + +exit 0 diff --git a/sonoStop.sh b/sonoStop.sh new file mode 100755 index 0000000..626df09 --- /dev/null +++ b/sonoStop.sh @@ -0,0 +1,5 @@ +#!/bin/bash + + +ssh pi@192.168.0.44 "/home/pi/script/enableMode.sh 4" >/dev/null 2>/dev/null + diff --git a/suncalc.php b/suncalc.php new file mode 100644 index 0000000..fd3a9dc --- /dev/null +++ b/suncalc.php @@ -0,0 +1,360 @@ +getTimestamp() / daySec - 0.5 + J1970; } +function fromJulian($j, $d) { + if (!is_nan($j)) { + $dt = new \DateTime("@".round(($j + 0.5 - J1970) * daySec)); + $dt->setTimezone($d->getTimezone()); + return $dt; + } +} +function toDays($date) { return toJulian($date) - J2000; } + +function rightAscension($l, $b) { return atan2(sin($l) * cos(e) - tan($b) * sin(e), cos($l)); } +function declination($l, $b) { return asin(sin($b) * cos(e) + cos($b) * sin(e) * sin($l)); } + +function azimuth($H, $phi, $dec) { return atan2(sin($H), cos($H) * sin($phi) - tan($dec) * cos($phi)); } +function altitude($H, $phi, $dec) { return asin(sin($phi) * sin($dec) + cos($phi) * cos($dec) * cos($H)); } + +function siderealTime($d, $lw) { return rad * (280.16 + 360.9856235 * $d) - $lw; } + +// calculations for sun times +function julianCycle($d, $lw) { return round($d - J0 - $lw / (2 * PI)); } + +function approxTransit($Ht, $lw, $n) { return J0 + ($Ht + $lw) / (2 * PI) + $n; } +function solarTransitJ($ds, $M, $L) { return J2000 + $ds + 0.0053 * sin($M) - 0.0069 * sin(2 * $L); } + +function hourAngle($h, $phi, $d) { return acos((sin($h) - sin($phi) * sin($d)) / (cos($phi) * cos($d))); } + +// returns set time for the given sun altitude +function getSetJ($h, $lw, $phi, $dec, $n, $M, $L) { + $w = hourAngle($h, $phi, $dec); + $a = approxTransit($w, $lw, $n); + return solarTransitJ($a, $M, $L); +} + +// general sun calculations +function solarMeanAnomaly($d) { return rad * (357.5291 + 0.98560028 * $d); } +function eclipticLongitude($M) { + + $C = rad * (1.9148 * sin($M) + 0.02 * sin(2 * $M) + 0.0003 * sin(3 * $M)); // equation of center + $P = rad * 102.9372; // perihelion of the Earth + + return $M + $C + $P + PI; +} + +function hoursLater($date, $h) { + $dt = clone $date; + return $dt->add( new DateInterval('PT'.round($h*3600).'S') ); +} + +class DecRa { + public $dec; + public $ra; + + function __construct($d, $r) { + $this->dec = $d; + $this->ra = $r; + } +} + +class DecRaDist extends DecRa { + public $dist; + + function __construct($d, $r, $dist) { + parent::__construct($d, $r); + $this->dist = $dist; + } +} + +class AzAlt { + public $azimuth; + public $altitude; + + function __construct($az, $alt) { + $this->azimuth = $az; + $this->altitude = $alt; + } +} + +class AzAltDist extends AzAlt { + public $dist; + + function __construct($az, $alt, $dist) { + parent::__construct($az, $alt); + $this->dist = $dist; + } +} + +function sunCoords($d) { + + $M = solarMeanAnomaly($d); + $L = eclipticLongitude($M); + + return new DecRa( + declination($L, 0), + rightAscension($L, 0) + ); +} + +function moonCoords($d) { // geocentric ecliptic coordinates of the moon + + $L = rad * (218.316 + 13.176396 * $d); // ecliptic longitude + $M = rad * (134.963 + 13.064993 * $d); // mean anomaly + $F = rad * (93.272 + 13.229350 * $d); // mean distance + + $l = $L + rad * 6.289 * sin($M); // longitude + $b = rad * 5.128 * sin($F); // latitude + $dt = 385001 - 20905 * cos($M); // distance to the moon in km + + return new DecRaDist( + declination($l, $b), + rightAscension($l, $b), + $dt + ); +} + + +class SunCalc { + + var $date; + var $lat; + var $lng; + + // sun times configuration (angle, morning name, evening name) + private $times = [ + [-0.833, 'sunrise', 'sunset' ], + [ -0.3, 'sunriseEnd', 'sunsetStart' ], + [ -6, 'dawn', 'dusk' ], + [ -12, 'nauticalDawn', 'nauticalDusk'], + [ -18, 'nightEnd', 'night' ], + [ 6, 'goldenHourEnd', 'goldenHour' ] + ]; + + // adds a custom time to the times config + private function addTime($angle, $riseName, $setName) { + $this->times[] = [$angle, $riseName, $setName]; + } + + function __construct($date, $lat, $lng) { + $this->date = $date; + $this->lat = $lat; + $this->lng = $lng; + } + + // calculates sun position for a given date and latitude/longitude + function getSunPosition() { + + $lw = rad * -$this->lng; + $phi = rad * $this->lat; + $d = toDays($this->date); + + $c = sunCoords($d); + $H = siderealTime($d, $lw) - $c->ra; + + return new AzAlt( + azimuth($H, $phi, $c->dec), + altitude($H, $phi, $c->dec) + ); + } + + // calculates sun times for a given date and latitude/longitude + function getSunTimes() { + + $lw = rad * -$this->lng; + $phi = rad * $this->lat; + + $d = toDays($this->date); + $n = julianCycle($d, $lw); + $ds = approxTransit(0, $lw, $n); + + $M = solarMeanAnomaly($ds); + $L = eclipticLongitude($M); + $dec = declination($L, 0); + + $Jnoon = solarTransitJ($ds, $M, $L); + + $result = [ + 'solarNoon'=> fromJulian($Jnoon, $this->date), + 'nadir' => fromJulian($Jnoon - 0.5, $this->date) + ]; + + for ($i = 0, $len = count($this->times); $i < $len; $i += 1) { + $time = $this->times[$i]; + + $Jset = getSetJ($time[0] * rad, $lw, $phi, $dec, $n, $M, $L); + $Jrise = $Jnoon - ($Jset - $Jnoon); + + $result[$time[1]] = fromJulian($Jrise, $this->date); + $result[$time[2]] = fromJulian($Jset, $this->date); + } + + return $result; + } + + + function getMoonPosition($date) { + $lw = rad * -$this->lng; + $phi = rad * $this->lat; + $d = toDays($date); + + $c = moonCoords($d); + $H = siderealTime($d, $lw) - $c->ra; + $h = altitude($H, $phi, $c->dec); + + // altitude correction for refraction + $h = $h + rad * 0.017 / tan($h + rad * 10.26 / ($h + rad * 5.10)); + + return new AzAltDist( + azimuth($H, $phi, $c->dec), + $h, + $c->dist + ); + } + + + function getMoonIllumination() { + + $d = toDays($this->date); + $s = sunCoords($d); + $m = moonCoords($d); + + $sdist = 149598000; // distance from Earth to Sun in km + + $phi = acos(sin($s->dec) * sin($m->dec) + cos($s->dec) * cos($m->dec) * cos($s->ra - $m->ra)); + $inc = atan2($sdist * sin($phi), $m->dist - $sdist * cos($phi)); + $angle = atan2(cos($s->dec) * sin($s->ra - $m->ra), sin($s->dec) * cos($m->dec) - cos($s->dec) * sin($m->dec) * cos($s->ra - $m->ra)); + + return [ + 'fraction' => (1 + cos($inc)) / 2, + 'phase' => 0.5 + 0.5 * $inc * ($angle < 0 ? -1 : 1) / PI, + 'angle' => $angle + ]; + } + + function getMoonTimes($inUTC=false) { + $t = clone $this->date; + if ($inUTC) $t->setTimezone(new \DateTimeZone('UTC')); + + $t->setTime(0, 0, 0); + + $hc = 0.133 * rad; + $h0 = $this->getMoonPosition($t, $this->lat, $this->lng)->altitude - $hc; + $rise = 0; + $set = 0; + + // go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set) + for ($i = 1; $i <= 24; $i += 2) { + $h1 = $this->getMoonPosition(hoursLater($t, $i), $this->lat, $this->lng)->altitude - $hc; + $h2 = $this->getMoonPosition(hoursLater($t, $i + 1), $this->lat, $this->lng)->altitude - $hc; + + $a = ($h0 + $h2) / 2 - $h1; + $b = ($h2 - $h0) / 2; + $xe = -$b / (2 * $a); + $ye = ($a * $xe + $b) * $xe + $h1; + $d = $b * $b - 4 * $a * $h1; + $roots = 0; + + if ($d >= 0) { + $dx = sqrt($d) / (abs($a) * 2); + $x1 = $xe - $dx; + $x2 = $xe + $dx; + if (abs($x1) <= 1) $roots++; + if (abs($x2) <= 1) $roots++; + if ($x1 < -1) $x1 = $x2; + } + + if ($roots === 1) { + if ($h0 < 0) $rise = $i + $x1; + else $set = $i + $x1; + + } else if ($roots === 2) { + $rise = $i + ($ye < 0 ? $x2 : $x1); + $set = $i + ($ye < 0 ? $x1 : $x2); + } + + if ($rise != 0 && $set != 0) break; + + $h0 = $h2; + } + + $result = []; + + if ($rise != 0) $result['moonrise'] = hoursLater($t, $rise); + if ($set != 0) $result['moonset'] = hoursLater($t, $set); + + if ($rise==0 && $set==0) $result[$ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true; + + return $result; + } +} + +// tests + +$test = new SunCalc(new \DateTime(), 47.7267025, -2.1319753); +#print_r($test->getSunTimes()); +print_r($test->getSunPosition()); +#print_r($test->getMoonIllumination()); +#print_r($test->getMoonTimes()); +#print_r(getMoonPosition(new \DateTime(), 48.85, 2.35)); + + +// Création d'une nouvelle ressource cURL +$ch = curl_init(); + +// Configuration de l'URL et d'autres options +curl_setopt($ch, CURLOPT_URL, "http://localhost:81/json.htm?type=command¶m=udevice&idx=321&nvalue=0&svalue=" . $test->getSunPosition()->azimuth * 180 / 3.14159); +curl_setopt($ch, CURLOPT_HEADER, 0); + +// Récupération de l'URL et affichage sur le navigateur +curl_exec($ch); + +// Configuration de l'URL et d'autres options +curl_setopt($ch, CURLOPT_URL, "http://localhost:81/json.htm?type=command¶m=udevice&idx=322&nvalue=0&svalue=" . $test->getSunPosition()->altitude * 180 / 3.14159); +curl_setopt($ch, CURLOPT_HEADER, 0); + +// Récupération de l'URL et affichage sur le navigateur +curl_exec($ch); +// Fermeture de la session cURL +curl_close($ch); diff --git a/support/README.md b/support/README.md new file mode 100644 index 0000000..725daa2 --- /dev/null +++ b/support/README.md @@ -0,0 +1,53 @@ + +# Domoticz support scripts + +## Index available support tools + +- [Get Domoticz version list](./README.md#get_build_versionssh) +- [MQTT AutoDiscovery tools](./mqtt_ad/README.md) + +## get_build_versions.sh + +**This script ONLY works when you run it from a subdirectory within the GITHUB clone of DOMOTICZ/DOMOTICZ.**\ +Script will list 20 commitlog entries preceding provided version, to easily list changes made around that version. + +### usage get_build_versions.sh + +```text +sh getcommitlog.sh [-v version] [-m max_logEntries] + -v domoticz version. default last + -m number of records to show. default 20 +``` + +### examples get_build_versions.sh + +```bash +#List last 20 versions & commit logrecords +sh getcommitlog.sh + +#List last 20 versions & commit logrecords for v41080 +sh getcommitlog.sh -v 41080 +*** Get 20 logrecords from commit:11974 version:14080 *** +Build Commit Date Commit Description +------ --------- ---------- ---------------------------------------------------------------------- +V14080 41e11f829 2022-01-17 Fix compile warning (and use internal reader) +V14079 6350f3544 2022-01-17 MQTT-AD: Escaping special characters +V14078 b120b0041 2022-01-17 Merge pull request #5113 from guillaumeclair/development +V14077 67c349a22 2022-01-17 Fixed compile warnings under windows +V14076 0f31858e1 2022-01-17 MQTT-AD: making sure correct discovery topic is matched (Fixes #5114) +V14075 7259c5139 2022-01-17 Fix a bug in variables name in alertlevel function +V14074 f64304efb 2022-01-16 Allow hardware to declare manual switches they are able to handle. (#4923) +V14073 4fcda55f3 2022-01-16 Partly fix for Meter Counter report +V14072 63e2f7b97 2022-01-16 MQTT/AD: Fixes for Fibaro FGRGBW dimmer (Issue #5069) (#5100) +V14071 f47572654 2022-01-16 MQTT-AD: Making sure JSON object is not a object +V14070 0bf7a176f 2022-01-15 MQTT-AD: putting unknown sensor types back into general type +V14069 b2a1ebf50 2022-01-15 MQTT-AD: Added more exception information +V14068 16801a0a4 2022-01-15 MQTT-AD: Added detection of CT nodes (needs more work from other pR) +V14067 b36f2bc65 2022-01-15 Replace light/switch now only transfers new HardwareID/DeviceID/Unit to the old device +V14066 13523bbe6 2022-01-15 Making sure a new sensor is created (could already exist a device with same type/id) +V14065 b66a52e13 2022-01-15 Updated History +V14064 650d91643 2022-01-15 Merge pull request #5111 from jgaalen/add-annathermostat-metrics +V14063 a3b03f315 2022-01-14 Add AnnaThermostat metrics +V14062 fce96f2a0 2022-01-14 Add AnnaThermostat metrics +V14061 d43fd6b3b 2022-01-14 Add Daikin yearly energy usage for kwh meter +``` diff --git a/support/get_build_versions.sh b/support/get_build_versions.sh new file mode 100644 index 0000000..d156b0a --- /dev/null +++ b/support/get_build_versions.sh @@ -0,0 +1,37 @@ +#!/bin/bash +: ' +# Scriptname getcommitlog.sh Ver: 20220123-02 +# Created by JvdZ +# base info from https://www.domoticz.com/forum/viewtopic.php?f=47&t=30405#p230094 + +Script will list 20 commitlog entries preceding provided version, to easily list changes made around that version + +usage: +sh getcommitlog.sh [-v version] [-m max_logEntries] + -v domoticz version. default last + -m number of records to show. default 20 +' + +MAXREC=20; +IVER="" +# process parameters +while getopts m:v: flag +do + case "${flag}" in + m) MAXREC=${OPTARG};; + v) IVER=${OPTARG};; + esac +done +# Get latest commit count +TCNT=`git rev-list HEAD --count` +# Version is Commitcount + 2107 use last when not provided as input +if [[ -z $IVER ]]; then + let IVER=TCNT+2107; +fi +# Calculate start record +let SREC=TCNT+2107-IVER +let SCOM=TCNT-SREC +echo " *** Get $MAXREC logrecords from commit:$SCOM version:$IVER ***" +echo "Build Commit Date Commit Description" +echo "------ --------- ---------- ----------------------------------------------------------------------" +git log --date=human --pretty=format:"%h %as %s" --skip=$SREC --max-count=$MAXREC | awk '{print "V"'$IVER'-NR+1 " " $s}' diff --git a/support/mqtt_ad/README.md b/support/mqtt_ad/README.md new file mode 100644 index 0000000..1ce0b79 --- /dev/null +++ b/support/mqtt_ad/README.md @@ -0,0 +1,79 @@ + +# MQTT AutoDiscovery tools + +## How to supply an MQTT AD messages dump to the developers + +When you are asked to supply a copy of all MQTT messages for a device used by MQTT Autodiscovery, you can follow the following steps: + + 1. go to subdirecory domoticz/scripts/support/mqtt_ad + 2. Run the script as shown in the examples below with the appropriate parameters. This will capture all MQTT packages in scope of the defined parametres. + 3. Provide us with the **mqtt_ad_record_*XXX*.log** file containing all records. + 4. Press Ctrl+c when you want to stop the capture process before the timer ends. + +## mqtt_ad_record.sh + +Script that helps capturing MQTT messages for Homeassistant AD into a file, so they can be shared easily with others for debugging. + +### usage mqtt_ad_record.sh + +```text +bash mqtt_ad_record.sh [-h hostname/ip] [-p port] [-s searchstring] [-t capturetime] + -h Hostname or Ipaddres of MQTT deamon. default is 127.0.0.1 + -p port for the MQTT deamon. default is 1883 + -u Userid for MQTT deamon + -P Password for MQTT deamon + -s only records MQTT messages that contain this string in the TOPIC or PAYLOAD. default is all messages + -t caputure time in seconds. default is 600 +``` + +### examples mqtt_ad_record.sh + +```bash + # Records all MQTT Messages containing "/config", "_state" or "/state" for 10 minutes + bash mqtt_ad_record.sh + + # specify userid and password to access the MQTT deamon. + bash mqtt_ad_record.sh -u UserId -P Password + + #Records all MQTT Messages containing "/config", "_state" or "/state" for 30 Seconds + bash mqtt_ad_record.sh -t 30 + + #Records all MQTT Messages containing "TASMOTA_A1" for 10 minutes + bash mqtt_ad_record.sh -s TASMOTA_A1 + + #Records all MQTT Messages containing "TASMOTA_A1" for 30 seconds + bash mqtt_ad_record.sh -s TASMOTA_A1 -t 30 +``` + +The above command will create an **mqtt_ad_record_*XXX*.log** file in the current directory. + +- where ***XXX*** will be ***all*** for the first 2 examples and will be ***TASMOTA_A1*** for the last 2 examples. + +## mqtt_ad_send.sh + +Script that sends the captured mqtt records again to a server recorded in HA_Discovery_mqtt.log in dezelfde directory. + +### usage mqtt_ad_send.sh + +```text +bash mqtt_ad_send.sh [-h hostname/ip] [-p port] [-s searchstring] [-i inputfile] + -h Hostname or Ipaddres of MQTT deamon. default is 127.0.0.1 + -p port for the MQTT deamon. default is 1883 + -s only send MQTT messages that contain this string in the TOPIC or PAYLOAD. default is all messages + -i inputfile. default is mqtt_ad_record_all.log + -r override retain (y/n). defaults to the retain flag in the input records + -d When Dry-run when switch is provided, no MQTT messages will be send, just the logging. +``` + +### examples mqtt_ad_send.sh + +```bash + #ALL records + bash mqtt_ad_send.sh + + #ALL records from a specific file + bash mqtt_ad_send.sh -i mqtt_ad_record_testDevice.log + + #Send selected records from log file: + bash mqtt_ad_send.sh PARTIAL_DEVICE_NAME +``` diff --git a/support/mqtt_ad/mqtt_ad_record.sh b/support/mqtt_ad/mqtt_ad_record.sh new file mode 100644 index 0000000..662d30a --- /dev/null +++ b/support/mqtt_ad/mqtt_ad_record.sh @@ -0,0 +1,102 @@ +#!/bin/bash +sver="20220124-01" +: ' +# Scriptname mqtt_ad_record.sh +# Created by JvdZ + +Script that helps capturing MQTT messages for Homeassistant AD into a file so they can be shared easily with others for debugging. + +usage: +bash mqtt_ad_record.sh [-h hostname/ip] [-p port] [-s searchstring] [-t*max capture time seconds*] + -h Hostname or Ipaddres of MQTT deamon. default is 127.0.0.1 + -p port for the MQTT deamon. default is 1883 + -u Userid for MQTT deamon + -P Password for MQTT deamon + -s only records MQTT messages that contain this string in the TOPIC or PAYLOAD. default is all messages + -t caputure time in seconds. default is 600 + +examples: + # Records all MQTT Messages containing "/config", "_state" or "/state" for 10 minutes. + bash mqtt_ad_record.sh + + # specify userid and password to access the MQTT deamon. + bash mqtt_ad_record.sh -u UserId -P Password + + #Records all MQTT Messages containing "/config", "_state" or "/state" for 30 Seconds. + bash mqtt_ad_record.sh -t 30 + + #Records all MQTT Messages containing "TASMOTA_A1" for 10 minutes. + bash mqtt_ad_record.sh -s TASMOTA_A1 + + #Records all MQTT Messages containing "TASMOTA_A1" for 30 seconds. + bash mqtt_ad_record.sh -s TASMOTA_A1 -t 30 + +Output file name: +The above commands will create file mqtt_ad_record_XXX.log in the current directory, + where XXX will be all for the first 2 examples and will be TASMOTA_A1 for the last 2 examples. +' + +MQTT_IP="127.0.0.1" # Define MQTT Server +MQTT_PORT="1883" # Define port +rtime=600 # Define default Capture time for MQTT messages in seconds. + # You can always interrupt the capture process at anytime withCtrl+Break pr Ctrl+C +MQTT_Param="" # used for extram mosquitto_sub parameters + +# Check if mosquitto_sub is installed +if ! command -v mosquitto_sub &> /dev/null; then + echo "=================================================================================================================" + echo "This script can be used to capture MQTT messages for a particular device." + echo "Current MQT Server $MQTT_IP port $MQTT_PORT, edit script to change these." + echo "!!!! program mosquitto_sub not found, please install that first." + echo "RPI install:sudo apt-get install mosquitto-clients" + echo "=================================================================================================================" + exit +fi +# process parameters +while getopts h:p:u:P:s:t: flag +do + case "${flag}" in + h) MQTT_IP=${OPTARG};; + p) MQTT_PORT=${OPTARG};; + u) MQTT_Param=${MQTT_Param}' -u '${OPTARG}'';; + P) MQTT_Param=${MQTT_Param}' -P '${OPTARG}'';; + s) sdev=${OPTARG};; + t) rtime=${OPTARG};; + esac +done + +# Set case insensitive flag for the PARTIAL_DEVICE_NAME tests +shopt -s nocasematch + +# trap ctrl-c and call ctrl_c() +trap message INT + +function message() { + echo "** CTRL-C pressed." + # command for clean up e.g. rm and so on goes below +} + +echo "== $sver ==============================================================================================================" +echo "MQTT_IP : '$MQTT_IP'"; +echo "MQTT_PORT : '$MQTT_PORT'"; +echo "MQTT_Param: '$MQTT_Param'"; +echo "Recordtime: '$rtime'"; +echo "Search For: '$sdev'"; + +logfile="mqtt_ad_record_all.log" +# Start Capture +if [[ -z $sdev ]]; then + echo "Start Capture for $rtime seconds of all MQTT messages to Console and file: $logfile" + mosquitto_sub $MQTT_Param -h $MQTT_IP -p $MQTT_PORT -t "#" -v -W $rtime -F "%I\t%r\t%t\t%p"| stdbuf -i0 -o0 grep -i -e "\/config\|[_\/]state" | stdbuf -i0 -o0 tee "$logfile" +else + # remove characters in filename that aren't allowed + logfile="mqtt_ad_record_"${sdev//[^A-Za-z0-9-_]/}".log" + echo "Start Capture for $rtime seconds of MQTT messages containing $sdev to Console and file: $logfile" + mosquitto_sub $MQTT_Param -h $MQTT_IP -p $MQTT_PORT -t "#" -v -W $rtime -F "%I\t%r\t%t\t%p"| stdbuf -i0 -o0 grep -i "$sdev" | stdbuf -i0 -o0 tee "$logfile" +fi +# Capture Ended +if [ "$?" -eq "0" ] ; then + echo "Capture ended, check file: $logfile" +else + echo "Capture interrupted, check file: $logfile" +fi \ No newline at end of file diff --git a/support/mqtt_ad/mqtt_ad_send.sh b/support/mqtt_ad/mqtt_ad_send.sh new file mode 100644 index 0000000..8acf631 --- /dev/null +++ b/support/mqtt_ad/mqtt_ad_send.sh @@ -0,0 +1,102 @@ +#!/bin/bash +sver="20220124-01" +: ' +# Scriptname mqtt_ad_send.sh +# Created by JvdZ + +Script that sends the captured mqtt records again to a server recorded in HA_Discovery_mqtt.log in dezelfde directory. + +usage: +bash mqtt_ad_send.sh [-h hostname/ip] [-p port] [-s searchstring] [-i inputfile] + -h Hostname or Ipaddres of MQTT deamon. default is 127.0.0.1 + -p port for the MQTT deamon. default is 1883 + -u Userid for MQTT deamon + -P Password for MQTT deamon + -s only send MQTT messages that contain this string in the TOPIC or PAYLOAD. default is all messages + -i inputfile. default is mqtt_ad_record_all.log + -r override retain (y/n). defaults to the retain flag in the record + -d When Dry-run when switch is provided, no MQTT messages will be send, just the logging. + +example: + ALL records : bash mqtt_ad_send.sh + Selected records: bash mqtt_ad_send.sh PARTIAL_DEVICE_NAME +' + +MQTT_IP="127.0.0.1" +MQTT_PORT="1883" +MQTT_Param="" +input="mqtt_ad_record_all.log" +retain="" +dryrun="" + +# process parameters +while getopts h:p:u:P:s:i:r:d flag +do + case "${flag}" in + h) MQTT_IP=${OPTARG};; + p) MQTT_PORT=${OPTARG};; + u) MQTT_Param=${MQTT_Param}' -u '${OPTARG};; + P) MQTT_Param=${MQTT_Param}' -P '${OPTARG};; + s) sdev=${OPTARG};; + i) input=${OPTARG};; + r) retain=${OPTARG};; + d) dryrun='y';; + esac +done + +# Set case insensitive flag for the PARTIAL_DEVICE_NAME tests +shopt -s nocasematch + +echo "== $sver ==============================================================================================================" +echo "MQTT_IP : '$MQTT_IP'"; +echo "MQTT_PORT : '$MQTT_PORT'"; +echo "MQTT_Param: '$MQTT_Param'"; +echo "inputfile : '$input'"; +if [[ ! -z "$retain" ]] ; then + echo "Retain override with '$retain'"; +fi +if [[ ! -z "$dryrun" ]] ; then + echo "### Dry-Run so no MQTT messages are send, just showing the log of the selected messages.###"; +fi + +srec=0; + +#Get rid of CR and only leave LF and read all records +# -r option read is to leave backslaches as in the file +cat "$input" | tr -d "\r" | while IFS=$'\t' read -r itime iretain itopic ipayload; +do + #echo -e "###\nT=$itopic\nP=$ipayload" + #skip Comment lines starting with # + [[ itime =~ ^#.* ]] && { continue; } + + #skip empty lines or only one param is provided + [[ -z "$ipayload" ]] && { continue; } + + #skip lines that do not contain the selected dev + [[ ! $itopic =~ $sdev ]] && { + [[ ! $ipayload =~ $sdev ]] && { continue; } + } + + ## process the selected record + srec=$((srec+1)) + # Set MQTT Options + MQTT_Opts="" + # Add Retain option when 1 is specified in input or in the override param -r + if [[ -z "$retain" ]] ; then + [[ "$iretain" == "1" ]] && { MQTT_Opts=" -r";} + else + [[ "$retain" == "y" ]] && { MQTT_Opts=" -r";} + fi + if [[ -z "$dryrun" ]] ; then + echo -e "== $srec > $MQTT_Opts\nT=$itopic\nP=$ipayload" + mosquitto_pub $MQTT_Param $MQTT_Opts -h $MQTT_IP -p $MQTT_PORT -t "$itopic" -m "$ipayload" + else + echo -e "-- $srec: $MQTT_Opts\nT=$itopic\nP=$ipayload" + fi +done + +if [[ ! -z "$dryrun" ]] ; then + echo "###============================================###"; + echo "### Dry-Run ended,so no MQTT messages are send.###"; + echo "###============================================###"; +fi diff --git a/templates/All.Lua b/templates/All.Lua new file mode 100644 index 0000000..3ef862f --- /dev/null +++ b/templates/All.Lua @@ -0,0 +1,50 @@ +-- +-- Domoticz passes information to scripts through a number of global tables +-- +-- otherdevices, otherdevices_lastupdate and otherdevices_svalues are arrays for all devices: +-- otherdevices['yourotherdevicename'] = "On" +-- otherdevices_lastupdate['yourotherdevicename'] = "2015-12-27 14:26:40" +-- otherdevices_svalues['yourotherthermometer'] = string of svalues +-- +-- uservariables and uservariables_lastupdate are arrays for all user variables: +-- uservariables['yourvariablename'] = 'Test Value' +-- uservariables_lastupdate['yourvariablename'] = '2015-12-27 11:19:22' +-- +-- other useful details are contained in the timeofday table +-- timeofday['Nighttime'] = true or false +-- timeofday['SunriseInMinutes'] = number +-- timeofday['Daytime'] = true or false +-- timeofday['SunsetInMinutes'] = number +-- globalvariables['Security'] = 'Disarmed', 'Armed Home' or 'Armed Away' +-- +-- To see examples of commands see: http://www.domoticz.com/wiki/LUA_commands#General +-- To get a list of available values see: http://www.domoticz.com/wiki/LUA_commands#Function_to_dump_all_variables_supplied_to_the_script +-- +-- Based on your logic, fill the commandArray with device commands. Device name is case sensitive. +-- +commandArray = {} + +print ("All based event fired"); +-- loop through all the devices +for deviceName,deviceValue in pairs(otherdevices) do +-- if (deviceName=='myDevice') then +-- if deviceValue == "On" then +-- print("Device is On") +-- elseif deviceValue == "Off" then +-- commandArray['a device name'] = "On" +-- commandArray['Scene:MyScene'] = "Off" +-- end +-- end +end + +-- loop through all the variables +for variableName,variableValue in pairs(uservariables) do +-- if (variableName=='myVariable') then +-- if variableValue == 1 then +-- commandArray['a device name'] = "On" +-- commandArray['Group:My Group'] = "Off AFTER 30" +-- end +-- end +end + +return commandArray diff --git a/templates/All.Python b/templates/All.Python new file mode 100644 index 0000000..b30cab7 --- /dev/null +++ b/templates/All.Python @@ -0,0 +1,76 @@ +""" +Domoticz passes information to python scripts through global variables and the +domoticz python module + +The global variables in the script are: + * changed_device: the current device that changed (object of Device) + * changed_device_name: name of current device (same as changed_device.name) + * is_daytime: boolean, true when it is is daytime + * is_nighttime: same for the night + * sunrise_in_minutes: integer + * sunset_in_minutes: integer + * user_variables: dictionary from string to value + +A Device has a number of attributes and methods +The attributes are: + * id + * name + * type + * sub_type + * switch_type + * n_value + * n_value_string + * s_value + * last_update_string + * last_update: datetime object + +The methods are: + * def last_update_was_ago(self, **kwargs): + Arguments can be: days[, seconds[, microseconds[, milliseconds[, minutes[, hours[, weeks] + * def is_on(self): + returns True when device is on + * def is_off(self): + returns True when device is ooff + + * def on(self, after=None, reflect=False): + turns device on, after is optional and are the number of seconds after which + to turn the device on. + If reflect is True, a next call to is_on will return True, while normally + domoticz will first have to go through possible script before turning it on + def off(self, after=None, reflect=False): + simular to on() + +uservariables and uservariables_lastupdate are arrays for all user variables: + uservariables['yourvariablename'] = 'Test Value' + uservariables_lastupdate['yourvariablename'] = '2015-12-27 11:19:22' + +other useful details are contained in the following global variables: + * is_daytime + * is_nighttime + * sunrise_in_minutes + * sunset_in_minutes + * (TODO) security + +Compare to Lua, instead of filling a commandArray, you change the status of a +device by calling device.on() or device.off() + +TODO: setting variables + +Calling Python's print function will not print to the domoticz console, see below +""" +import DomoticzEvents as DE + +DE.Log("Python: Changed: " + DE.changed_device.Describe()) + +if DE.changed_device_name == "Test": + if DE.Devices["Test_Target"].n_value_string == "On": + DE.Command("Test_Target", "Off") + + if DE.Devices["Test_Target"].n_value_string == "Off": + DE.Command("Test_Target", "On") + +DE.Log("Python: Number of user_variables: " + str(len(DE.user_variables))) + +# All user_variables are treated as strings, convert as necessary +for key, value in DE.user_variables.items(): + DE.Log("Python: User-variable '{0}' has value: {1}".format(key, value)) diff --git a/templates/All.dzVents b/templates/All.dzVents new file mode 100644 index 0000000..fe22952 --- /dev/null +++ b/templates/All.dzVents @@ -0,0 +1,124 @@ +-- Check the wiki for dzVents +-- remove what you don't need +return { + + -- optional active section, + -- when left out the script is active + -- note that you still have to check this script + -- as active in the side panel + active = { + + true, -- either true or false, or you can specify a function + + --function(domoticz) + -- return true/false + --end + }, + -- trigger + -- can be a combination: + on = { + + -- device triggers + devices = { + -- scripts is executed if the device that was updated matches with one of these triggers + 'device name', -- device name + 'abc*', -- triggers for all devices which name begins with abc + 258, -- id + }, + + -- timer riggers + timer = { + -- timer triggers.. if one matches with the current time then the script is executed + 'at 13:45', + 'at 18:37', + 'every 3 minutes on mon,tue,fri at 16:00-15:00', + function(domoticz) + -- return true or false + end + }, + + -- user variable triggers + variables = { + 'myUserVariable' + }, + + -- security triggers + security = { + domoticz.SECURITY_ARMEDAWAY, + domoticz.SECURITY_ARMEHOME, + }, + + -- scene triggers + scenes = { + 'myScene' + }, + + -- group triggers + groups = { + 'myGroup' + }, + + -- http responses + httpResponses = { + 'some callback string' + }, + + -- shell commmand responses + shellCommandResponses = { + 'another callback string' + }, + + -- system events + system = { + 'start', + 'stop', + 'manualBackupFinished', + 'dailyBackupFinished', + 'hourlyBackupFinished', + 'monthlyBackupFinished' + }, + + customEvents = { + 'myCustomEvent' + } + }, + + -- persistent data + -- see documentation about persistent variables + data = { + myVar = { initial = 5 }, + myHistoryVar = { maxItems = 10 }, + }, + + -- custom logging level for this script + logging = { + level = domoticz.LOG_INFO, + marker = "template" + }, + + -- actual event code + -- the second parameter is depending on the trigger + -- when it is a device change, the second parameter is the device object + -- similar for variables, scenes and groups and httpResponses + -- inspect the type like: triggeredItem.isDevice + execute = function(domoticz, triggeredItem, info) + --[[ + + The domoticz object holds all information about your Domoticz system. E.g.: + + local myDevice = domoticz.devices('myDevice') + local myVariable = domoticz.variables('myUserVariable') + local myGroup = domoticz.groups('myGroup') + local myScene = domoticz.scenes('myScene') + + The device object is the device that was triggered due to the device in the 'on' section above. + ]] -- + + -- example + + if (triggerdItem.active) then -- state == 'On' + triggerdItem.switchOff().afterMin(2) -- if it is a switch + domoticz.notify('Light info', 'The light ' .. triggerdItem.name .. ' will be switched off soon') + end + end +} diff --git a/templates/Bare.dzVents b/templates/Bare.dzVents new file mode 100644 index 0000000..6cc8e48 --- /dev/null +++ b/templates/Bare.dzVents @@ -0,0 +1,19 @@ +return { + on = { + devices = {}, + timer = {}, + variables = {}, + scenes = {}, + groups = {}, + security = {}, + httpResponses = {}, + shellCommandResponses = {}, + customEvents = {}, + system = {}, + }, + data = {}, + logging = {}, + execute = function(domoticz, triggeredItem) + + end +} diff --git a/templates/CustomEvents.dzVents b/templates/CustomEvents.dzVents new file mode 100644 index 0000000..b21fc2c --- /dev/null +++ b/templates/CustomEvents.dzVents @@ -0,0 +1,20 @@ +return { + on = { + timer = { + 'every 5 minutes' -- just an example to trigger the event + }, + customEvents = { + 'MyEvent' -- event triggered by emitEvent + } + }, + data = {}, + logging = {}, + execute = function(domoticz, triggeredItem) + if (triggeredItem.isCustomEvent) then + domoticz.log(triggeredItem.data) + else + -- second parameter can be anything, number, string, boolean or table + domoticz.emitEvent('MyEvent', 'Some data') + end + end +} diff --git a/templates/Device.Lua b/templates/Device.Lua new file mode 100644 index 0000000..e3b7ba3 --- /dev/null +++ b/templates/Device.Lua @@ -0,0 +1,46 @@ +-- +-- Domoticz passes information to scripts through a number of global tables +-- +-- device changed contains state and svalues for the device that changed. +-- devicechanged['yourdevicename'] = state +-- devicechanged['svalues'] = svalues string +-- +-- otherdevices, otherdevices_lastupdate and otherdevices_svalues are arrays for all devices: +-- otherdevices['yourotherdevicename'] = "On" +-- otherdevices_lastupdate['yourotherdevicename'] = "2015-12-27 14:26:40" +-- otherdevices_svalues['yourotherthermometer'] = string of svalues +-- +-- uservariables and uservariables_lastupdate are arrays for all user variables: +-- uservariables['yourvariablename'] = 'Test Value' +-- uservariables_lastupdate['yourvariablename'] = '2015-12-27 11:19:22' +-- +-- other useful details are contained in the timeofday table +-- timeofday['Nighttime'] = true or false +-- timeofday['SunriseInMinutes'] = number +-- timeofday['Daytime'] = true or false +-- timeofday['SunsetInMinutes'] = number +-- globalvariables['Security'] = 'Disarmed', 'Armed Home' or 'Armed Away' +-- +-- To see examples of commands see: http://www.domoticz.com/wiki/LUA_commands#General +-- To get a list of available values see: http://www.domoticz.com/wiki/LUA_commands#Function_to_dump_all_variables_supplied_to_the_script +-- +-- Based on your logic, fill the commandArray with device commands. Device name is case sensitive. +-- +commandArray = {} + +-- loop through all the changed devices +for deviceName,deviceValue in pairs(devicechanged) do + print ("Device based event fired on '"..deviceName.."', value '"..tostring(deviceValue).."'"); +-- if (deviceName=='myDevice') then +-- if deviceValue == "On" then +-- print("Device is On") +-- elseif deviceValue == "Off" then +-- commandArray['a device name'] = "On" +-- commandArray['another device name'] = "Off AFTER 10" +-- commandArray['Scene:MyScene'] = "Off" +-- commandArray['Group:My Group'] = "Off AFTER 30" +-- end +-- end +end + +return commandArray diff --git a/templates/Device.dzVents b/templates/Device.dzVents new file mode 100644 index 0000000..7e31094 --- /dev/null +++ b/templates/Device.dzVents @@ -0,0 +1,14 @@ +return { + on = { + devices = { + 'myDevice' + } + }, + logging = { + level = domoticz.LOG_INFO, + marker = 'template', + }, + execute = function(domoticz, device) + domoticz.log('Device ' .. device.name .. ' was changed', domoticz.LOG_INFO) + end +} \ No newline at end of file diff --git a/templates/ExecuteShellCommand.dzVents b/templates/ExecuteShellCommand.dzVents new file mode 100644 index 0000000..6242d77 --- /dev/null +++ b/templates/ExecuteShellCommand.dzVents @@ -0,0 +1,45 @@ +local myResponse + +return { + on = { + devices = { + 'test' + }, + shellCommandResponses = { + 'myResponse', -- must match with the callback passed to the executeShellCommand + }, + }, + logging = { + level = domoticz.LOG_INFO, + marker = 'template', + }, + execute = function(domoticz, item) + + if (item.isDevice) then + domoticz.executeShellCommand({ + command = 'speedtest-cli --json', -- just an example + callback = 'myResponse', -- see shellCommandResponses above. + timeout = 50, -- Max runtime 50 seconds + }) + end + + if (item.isShellCommandResponse) then + + if (item.statusCode==0) then + if (item.isJSON) then + + domoticz.log('Download speed is '.. item.json.download,domoticz.LOG_INFO) -- just an example + + -- update some device in Domoticz + domoticz.devices('myTextDevice').updateText(someValue) + end + else + domoticz.log('There was a problem handling the request', domoticz.LOG_ERROR) + domoticz.log(item, domoticz.LOG_ERROR) + end + + end + + end +} + diff --git a/templates/Group.dzVents b/templates/Group.dzVents new file mode 100644 index 0000000..43afe33 --- /dev/null +++ b/templates/Group.dzVents @@ -0,0 +1,14 @@ +return { + on = { + groups = { + 'myGroup' + } + }, + logging = { + level = domoticz.LOG_INFO, + marker = 'template', + }, + execute = function(domoticz, group) + domoticz.log('Group ' .. group.name .. ' was changed', domoticz.LOG_INFO) + end +} \ No newline at end of file diff --git a/templates/HTTPRequest.dzVents b/templates/HTTPRequest.dzVents new file mode 100644 index 0000000..98a3205 --- /dev/null +++ b/templates/HTTPRequest.dzVents @@ -0,0 +1,42 @@ +return { + on = { + timer = { + 'every 5 minutes' -- just an example to trigger the request + }, + httpResponses = { + 'trigger' -- must match with the callback passed to the openURL command + } + }, + logging = { + level = domoticz.LOG_INFO, + marker = 'template', + }, + execute = function(domoticz, item) + + if (item.isTimer) then + domoticz.openURL({ + url = 'http://somedomain/someAPI?param=1', + method = 'GET', + callback = 'trigger', -- see httpResponses above. + }) + end + + if (item.isHTTPResponse) then + + if (item.ok) then + if (item.isJSON) then + + local someValue = item.json.someValue -- just an example + + -- update some device in Domoticz + domoticz.devices('myTextDevice').updateText(someValue) + end + else + domoticz.log('There was a problem handling the request', domoticz.LOG_ERROR) + domoticz.log(item, domoticz.LOG_ERROR) + end + + end + + end +} diff --git a/templates/Scene.dzVents b/templates/Scene.dzVents new file mode 100644 index 0000000..3ab16f4 --- /dev/null +++ b/templates/Scene.dzVents @@ -0,0 +1,14 @@ +return { + on = { + scenes = { + 'myScene' + } + }, + logging = { + level = domoticz.LOG_INFO, + marker = 'template', + }, + execute = function(domoticz, scene) + domoticz.log('Scene ' .. scene.name .. ' was changed', domoticz.LOG_INFO) + end +} \ No newline at end of file diff --git a/templates/Security.Lua b/templates/Security.Lua new file mode 100644 index 0000000..b663eb7 --- /dev/null +++ b/templates/Security.Lua @@ -0,0 +1,50 @@ +-- +-- Domoticz passes information to scripts through a number of global tables +-- +-- otherdevices, otherdevices_lastupdate and otherdevices_svalues are arrays for all devices: +-- otherdevices['yourotherdevicename'] = "On" +-- otherdevices_lastupdate['yourotherdevicename'] = "2015-12-27 14:26:40" +-- otherdevices_svalues['yourotherthermometer'] = string of svalues +-- +-- uservariables and uservariables_lastupdate are arrays for all user variables: +-- uservariables['yourvariablename'] = 'Test Value' +-- uservariables_lastupdate['yourvariablename'] = '2015-12-27 11:19:22' +-- +-- other useful details are contained in the timeofday table +-- timeofday['Nighttime'] = true or false +-- timeofday['SunriseInMinutes'] = number +-- timeofday['Daytime'] = true or false +-- timeofday['SunsetInMinutes'] = number +-- globalvariables['Security'] = 'Disarmed', 'Armed Home' or 'Armed Away' +-- +-- To see examples of commands see: http://www.domoticz.com/wiki/LUA_commands#General +-- To get a list of available values see: http://www.domoticz.com/wiki/LUA_commands#Function_to_dump_all_variables_supplied_to_the_script +-- +-- Based on your logic, fill the commandArray with device commands. Device name is case sensitive. +-- +commandArray = {} + +print ("Security based event fired"); +-- loop through all the devices +for deviceName,deviceValue in pairs(otherdevices) do +-- if (deviceName=='myDevice') then +-- if deviceValue == "On" then +-- print("Device is On") +-- elseif deviceValue == "Off" then +-- commandArray['a device name'] = "On" +-- commandArray['Scene:MyScene'] = "Off" +-- end +-- end +end + +-- loop through all the variables +for variableName,variableValue in pairs(uservariables) do +-- if (variableName=='myVariable') then +-- if variableValue == 1 then +-- commandArray['a device name'] = "On" +-- commandArray['Group:My Group'] = "Off AFTER 30" +-- end +-- end +end + +return commandArray diff --git a/templates/Security.dzVents b/templates/Security.dzVents new file mode 100644 index 0000000..6fea2a8 --- /dev/null +++ b/templates/Security.dzVents @@ -0,0 +1,14 @@ +return { + on = { + security = { + domoticz.SECURITY_ARMEDAWAY, + } + }, + logging = { + level = domoticz.LOG_INFO, + marker = 'template', + }, + execute = function(domoticz, security) + domoticz.log('Security was triggered by ' .. security.trigger, domoticz.LOG_INFO) + end +} diff --git a/templates/Seurity.dzVents b/templates/Seurity.dzVents new file mode 100644 index 0000000..4a16597 --- /dev/null +++ b/templates/Seurity.dzVents @@ -0,0 +1,13 @@ +return { + active = false, + on = { + security = { + domoticz.SECURITY_ARMEDAWAY, + } + }, + data = {}, + execute = function(domoticz, dummy, info) + domoticz.log('Security was triggered by ' .. info.trigger, domoticz.LOG_INFO) + -- code + end +} \ No newline at end of file diff --git a/templates/System.dzVents b/templates/System.dzVents new file mode 100644 index 0000000..8eb4617 --- /dev/null +++ b/templates/System.dzVents @@ -0,0 +1,19 @@ +return { + on = { + system = { + 'start', + 'stop', + 'manualBackupFinished', + 'dailyBackupFinished', + 'hourlyBackupFinished', + 'monthlyBackupFinished', + }, + }, + logging = { + level = domoticz.LOG_INFO, + marker = 'template', + }, + execute = function(domoticz, triggeredItem) + domoticz.log('Domoticz has started') + end +} diff --git a/templates/Time.Lua b/templates/Time.Lua new file mode 100644 index 0000000..2e0cd22 --- /dev/null +++ b/templates/Time.Lua @@ -0,0 +1,51 @@ +-- +-- Domoticz passes information to scripts through a number of global tables +-- +-- otherdevices, otherdevices_lastupdate and otherdevices_svalues are arrays for all devices: +-- otherdevices['yourotherdevicename'] = "On" +-- otherdevices_lastupdate['yourotherdevicename'] = "2015-12-27 14:26:40" +-- otherdevices_svalues['yourotherthermometer'] = string of svalues +-- +-- uservariables and uservariables_lastupdate are arrays for all user variables: +-- uservariables['yourvariablename'] = 'Test Value' +-- uservariables_lastupdate['yourvariablename'] = '2015-12-27 11:19:22' +-- +-- other useful details are contained in the timeofday table +-- timeofday['Nighttime'] = true or false +-- timeofday['SunriseInMinutes'] = number +-- timeofday['Daytime'] = true or false +-- timeofday['SunsetInMinutes'] = number +-- globalvariables['Security'] = 'Disarmed', 'Armed Home' or 'Armed Away' +-- +-- To see examples of commands see: http://www.domoticz.com/wiki/LUA_commands#General +-- To get a list of available values see: http://www.domoticz.com/wiki/LUA_commands#Function_to_dump_all_variables_supplied_to_the_script +-- +-- Based on your logic, fill the commandArray with device commands. Device name is case sensitive. +-- + +commandArray = {} + +print ("Time based event fired"); +-- loop through all the devices +for deviceName,deviceValue in pairs(otherdevices) do +-- if (deviceName=='myDevice') then +-- if deviceValue == "On" then +-- print("Device is On") +-- elseif deviceValue == "Off" then +-- commandArray['a device name'] = "On" +-- commandArray['Scene:MyScene'] = "Off" +-- end +-- end +end + +-- loop through all the variables +for variableName,variableValue in pairs(uservariables) do +-- if (variableName=='myVariable') then +-- if variableValue == 1 then +-- commandArray['a device name'] = "On" +-- commandArray['Group:My Group'] = "Off AFTER 30" +-- end +-- end +end + +return commandArray diff --git a/templates/Timer.dzVents b/templates/Timer.dzVents new file mode 100644 index 0000000..e05406c --- /dev/null +++ b/templates/Timer.dzVents @@ -0,0 +1,54 @@ +return { + on = { + timer = { + 'every minute', -- causes the script to be called every minute + 'every other minute', -- minutes: xx:00, xx:02, xx:04, ..., xx:58 + 'every minutes', -- starting from xx:00 triggers every xx minutes (0 > xx < 60) + 'every hour', -- 00:00, 01:00, ..., 23:00 (24x per 24hrs) + 'every other hour', -- 00:00, 02:00, ..., 22:00 (12x per 24hrs) + 'every hours', -- starting from 00:00, triggers every xx hours (0 > xx < 24) + 'at 13:45', -- specific time + 'at *:45', -- every 45th minute in the hour + 'at 15:*', -- every minute between 15:00 and 16:00 + 'at 12:45-21:15', -- between 12:45 and 21:15. You cannot use '*'! + 'at 19:30-08:20', -- between 19:30 and 8:20 then next day + 'at 13:45 on mon,tue', -- at 13:45 only on Monday en Tuesday (english) + 'every hour on sat', -- you guessed it correctly + 'at sunset', -- uses sunset/sunrise info from Domoticz + 'at sunrise', + 'at sunset on sat,sun', + 'xx minutes before sunset', + 'xx minutes after sunset', + 'xx minutes before sunrise', + 'xx minutes after sunrise', -- guess ;-) + 'between aa and bb', -- aa/bb can be a time stamp like 15:44 + -- aa/bb can be sunrise/sunset + -- aa/bb can be 'xx minutes before/after + -- sunrise/sunset' + 'at nighttime', -- between sunset and sunrise + 'at daytime', -- between sunrise and sunset + 'at civildaytime', -- between civil twilight start and civil twilight end + 'at civilnighttime', -- between civil twilight end and civil twilight start + 'at daytime on mon,tue', -- between sunrise and sunset only on monday and tuesday + + -- or if you want to go really wild: + 'at nighttime at 21:32-05:44 every 5 minutes on sat, sun', + 'every 10 minutes between 20 minutes before sunset and 30 minutes after sunrise on mon,fri,tue', + + -- or just do it yourself: + function(domoticz) + -- you can use domoticz.time to get the current time + -- note that this function is called every minute! + -- custom code that either returns true or false + return true + end, + } + }, + logging = { + level = domoticz.LOG_INFO, + marker = 'template', + }, + execute = function(domoticz, timer) + domoticz.log('Timer event was triggered by ' .. timer.trigger, domoticz.LOG_INFO) + end +} diff --git a/templates/Timer.dzvents b/templates/Timer.dzvents new file mode 100644 index 0000000..e5d645c --- /dev/null +++ b/templates/Timer.dzvents @@ -0,0 +1,53 @@ +return { + on = { + timer = { + 'every minute', -- causes the script to be called every minute + 'every other minute', -- minutes: xx:00, xx:02, xx:04, ..., xx:58 + 'every minutes', -- starting from xx:00 triggers every xx minutes + -- (0 > xx < 60) + 'every hour', -- 00:00, 01:00, ..., 23:00 (24x per 24hrs) + 'every other hour', -- 00:00, 02:00, ..., 22:00 (12x per 24hrs) + 'every hours', -- starting from 00:00, triggers every xx + -- hours (0 > xx < 24) + 'at 13:45', -- specific time + 'at *:45', -- every 45th minute in the hour + 'at 15:*', -- every minute between 15:00 and 16:00 + 'at 12:45-21:15', -- between 12:45 and 21:15. You cannot use '*'! + 'at 19:30-08:20', -- between 19:30 and 8:20 then next day + 'at 13:45 on mon,tue', -- at 13:45 only on Monday en Tuesday (english) + 'every hour on sat', -- you guessed it correctly + 'at sunset', -- uses sunset/sunrise info from Domoticz + 'at sunrise', + 'at sunset on sat,sun', + 'xx minutes before sunset', + 'xx minutes after sunset', + 'xx minutes before sunrise', + 'xx minutes after sunrise' -- guess ;-) + 'between aa and bb' -- aa/bb can be a time stamp like 15:44 + -- aa/bb can be sunrise/sunset + -- aa/bb can be 'xx minutes before/after + -- sunrise/sunset' + 'at nighttime', -- between sunset and sunrise + 'at daytime', -- between sunrise and sunset + 'at civildaytime', -- between civil twilight start and civil twilight end + 'at civilnighttime', -- between civil twilight end and civil twilight start + 'at daytime on mon,tue', -- between sunrise and sunset + -- only on monday and tuesday + + -- or if you want to go really wild: + 'at nighttime at 21:32-05:44 every 5 minutes on sat, sun', + 'every 10 minutes between 20 minutes before sunset and 30 minutes after sunrise on mon,fri,tue' + + -- or just do it yourself: + function(domoticz) + -- you can use domoticz.time to get the current time + -- note that this function is called every minute! + -- custom code that either returns true or false + return true + end + }, + }, + execute = function(domoticz, timer) + domoticz.log('Timer event was triggered by ' .. timer.trigger, domoticz.LOG_INFO) + end +} diff --git a/templates/UserVariable.Lua b/templates/UserVariable.Lua new file mode 100644 index 0000000..e2c8299 --- /dev/null +++ b/templates/UserVariable.Lua @@ -0,0 +1,42 @@ +-- +-- Domoticz passes information to scripts through a number of global tables +-- +-- variable changed contains state and svalues for the variable that changed. +-- uservariablechanged['yourvariablename'] = value +-- +-- otherdevices, otherdevices_lastupdate and otherdevices_svalues are arrays for all devices: +-- otherdevices['yourotherdevicename'] = "On" +-- otherdevices_lastupdate['yourotherdevicename'] = "2015-12-27 14:26:40" +-- otherdevices_svalues['yourotherthermometer'] = string of svalues +-- +-- uservariables and uservariables_lastupdate are arrays for all user variables: +-- uservariables['yourvariablename'] = 'Test Value' +-- uservariables_lastupdate['yourvariablename'] = '2015-12-27 11:19:22' +-- +-- other useful details are contained in the timeofday table +-- timeofday['Nighttime'] = true or false +-- timeofday['SunriseInMinutes'] = number +-- timeofday['Daytime'] = true or false +-- timeofday['SunsetInMinutes'] = number +-- globalvariables['Security'] = 'Disarmed', 'Armed Home' or 'Armed Away' +-- +-- To see examples of commands see: http://www.domoticz.com/wiki/LUA_commands#General +-- To get a list of available values see: http://www.domoticz.com/wiki/LUA_commands#Function_to_dump_all_variables_supplied_to_the_script +-- +-- Based on your logic, fill the commandArray with device commands. Device name is case sensitive. +-- +commandArray = {} + +-- loop through all the changed variables +for variableName,variableValue in pairs(uservariablechanged) do + print ("Variable based event fired on '"..variableName.."', value '"..tostring(variableValue).."'"); +-- if (variableName=='myVariable') then +-- if variableValue == 1 then +-- commandArray['a device name'] = "On" +-- commandArray['another device name'] = "Off AFTER 10" +-- commandArray['Variable:myVariable'] = 'new value' +-- end +-- end +end + +return commandArray \ No newline at end of file diff --git a/templates/UserVariable.dzVents b/templates/UserVariable.dzVents new file mode 100644 index 0000000..292b5a4 --- /dev/null +++ b/templates/UserVariable.dzVents @@ -0,0 +1,15 @@ +return { + on = { + variables = { + 'myUserVariable', + }, + }, + logging = { + level = domoticz.LOG_INFO, + marker = 'template', + }, + execute = function(domoticz, variable) + domoticz.log('Variable ' .. variable.name .. ' was changed', domoticz.LOG_INFO) + -- code + end +} \ No newline at end of file diff --git a/templates/global_data.dzVents b/templates/global_data.dzVents new file mode 100644 index 0000000..4a94f25 --- /dev/null +++ b/templates/global_data.dzVents @@ -0,0 +1,18 @@ +-- this scripts holds all the globally persistent variables and helper functions +-- see the documentation in the wiki +-- NOTE: +-- THERE CAN BE ONLY ONE global_data SCRIPT in your Domoticz install. + +return { + -- global persistent data + data = { + myGlobalVar = { initial = 12 } + }, + + -- global helper functions + helpers = { + myHelperFunction = function(domoticz) + -- code + end + } +} diff --git a/test b/test new file mode 100644 index 0000000..e69de29 diff --git a/test.lua b/test.lua new file mode 100644 index 0000000..582f708 --- /dev/null +++ b/test.lua @@ -0,0 +1,38 @@ +function dump(o) + if type(o) == 'table' then + local s = '{ ' + for k,v in pairs(o) do + if type(k) ~= 'number' then k = '"'..k..'"' end + s = s .. '['..k..'] = ' .. dump(v) .. ',' + end + return s .. '} ' + else + return tostring(o) + end +end + +function dumpKey(o, to_print) + if type(o) == 'table' then + for k,v in pairs(o) do + dumpKey(v, to_print..' '..k) + end + else + print(to_print..' '..tostring(o)) + end +end + +json = (loadfile "/home/souti/domoticz/scripts/lua/JSON.lua")() + + local f = assert(io.open("/tmp/Devices.txt","r")) + local livebox = f:read('*all') + f:close() + --Décodage ud fichier + local jsonLivebox = json:decode(livebox) + --print(dumpKey(jsonLivebox, '')) +devices = jsonLivebox["status"] +--print(dump(devices)) +for k,status in pairs(devices) do + print("---"..k.."-------"..status["Name"].."--"..tostring(status["Active"])) + print(dumpKey(status, '')) + --print("Name : "..status['name']) --.." IP : "..status['ipAddress'].." "..tostring(status['active'])) +end diff --git a/test.php b/test.php new file mode 100644 index 0000000..03337c4 --- /dev/null +++ b/test.php @@ -0,0 +1,25 @@ + $value) { + echo str_repeat(' ', $indentation); // Indentation pour une meilleure visualisation + + if (is_array($value)) { + echo "$key => \n"; + afficherArbre($value, $indentation + 1); // Appel récursif pour les sous-tableaux + } else { + echo "$key => $value\n"; + } + } +} + +// URL contenant le JSON +$url = 'http://api.openweathermap.org/data/2.5/weather?q=La Gacilly,fr&APPID=feba3f4d926db3b358a25ec782bd1c8b&lang=FR&units=metric'; // Remplacez par votre URL JSON + +// Récupération de la réponse JSON +$response = file_get_contents($url); + +afficherArbre(json_decode($response,true)); +?> + diff --git a/test2.lua b/test2.lua new file mode 100644 index 0000000..e3b0259 --- /dev/null +++ b/test2.lua @@ -0,0 +1,72 @@ +-- ~/domoticz/scripts/lua/script_device_increaselight.lua +-- On pressing a single button, script reads current light level +-- and increases by 1 dimming level + + +function dump(o) + if type(o) == 'table' then + local s = '{ ' + for k,v in pairs(o) do + if type(k) ~= 'number' then k = '"'..k..'"' end + s = s .. '['..k..'] = ' .. dump(v) .. ',' + end + return s .. '} ' + else + return tostring(o) + end +end + +function os.capture(cmd, raw) + local f = assert(io.popen(cmd, 'r')) + local s = assert(f:read('*a')) + f:close() + if raw then return s end + s = string.gsub(s, '^%s+', '') + s = string.gsub(s, '%s+$', '') + s = string.gsub(s, '[\n\r]+', ' ') + return s +end +decodeurjson = (loadfile "/home/souti/domoticz/scripts/lua/JSON.lua")() + +commandArray = {} +-- Path to curl +local curl = '/usr/bin/curl' +-- Device ID +local idx = '493' +--serveur domoticz +dz = "192.168.1.3:81" + +local cmd = curl .. ' "http://'..dz..'/json.htm?type=devices&rid='..idx..'"' +local json = os.capture(cmd , false) +donneesJson = decodeurjson:decode(json) +print(dump(donneesJson)) +level = donneesJson['result'] +print(dump(level)) +print('json: ' .. donneesJson['result'][1]["Level"]) + + + +commandArray = {} +-- No of dimming steps of device +MaxDimLevel = 100 +step = 100.0 / MaxDimLevel +increment = 10 +button = 'dimmapp' +light = 'Appliques' +if (devicechanged[button]) then + -- Need to test for not "Off" rather than "On", as when light + -- on svalue can be "On" or "Set Level" + if ('Off' ~= string.len(otherdevices_svalues[light])) then + local Level = tonumber(Level) + if (Level < MaxDimLevel) then + Level = step * Level + newlevel = mat.ceil(level + (increment * step)) + print('Increase ' .. light .. ' from ' .. math.ceil(Level) .. '% to ' .. newlevel .. '%') + commandArray[light]='Set Level ' .. newlevel + end + end +end + +return commandArray + + diff --git a/test2.php b/test2.php new file mode 100644 index 0000000..9398d64 --- /dev/null +++ b/test2.php @@ -0,0 +1,65 @@ +loadHTML($htmlContent); + $xpath = new DOMXPath($doc); + + // Rechercher les éléments avec la classe "timetable-container" + $elements = $xpath->query('//div[contains(@class, "timetable-container")]'); + + // Créer un tableau pour stocker les données extraites + $data = array(); + + // Parcourir les éléments et extraire le contenu + foreach ($elements as $element) { + $data[] = $element->nodeValue; + } + + return $data; +} + +// Récupérer le contenu HTML de l'URL +$htmlContent = getHTMLContent($url); + +// Extraire les données de la classe HTML "timetable-container" +$data = extractDataFromHTML($htmlContent); + +// Convertir les données en format JSON +$jsonData = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); + +// Afficher le JSON résultant +header('Content-Type: application/json'); +//echo $jsonData; +#$data = explode("\n", $data); +$data = json_decode($jsonData, true); + +// Suppression des caractères "\n" dans les valeurs du tableau +/*$data = array_map(function ($value) { + if (is_string($value)) { + return str_replace("\n", "", $value); + } + return $value; +}, $data);*/ + +// Affichage du tableau résultant +print_r($data); +?> + diff --git a/testAlarme.sh b/testAlarme.sh new file mode 100755 index 0000000..c40ccf0 --- /dev/null +++ b/testAlarme.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +echo "Alarme On" >>/tmp/log diff --git a/tuya/Victron.py b/tuya/Victron.py new file mode 100644 index 0000000..3f73b78 --- /dev/null +++ b/tuya/Victron.py @@ -0,0 +1,31 @@ +import requests +import json +import prettytable as pt + +# URL de l'API +url = "http://192.168.1.49/getVictron" + +# Faire la requete GET +response = requests.get(url) + +# Verifier que la requete a reussi +if response.status_code == 200: + # Charger le JSON recu + data = response.json() + + # Creer un tableau PrettyTable + table = pt.PrettyTable() + table.field_names = ["ID", "Key Label", "Label", "Value"] + + # Ajouter les lignes au tableau + for item in data: + table.add_row([ + item.get("id", "N/A"), + item.get("key_label", "N/A"), + item.get("label", "N/A"), + item.get("value", "N/A") + ]) + # Afficher le tableau + print(table) + + diff --git a/tuya/device.py b/tuya/device.py new file mode 100644 index 0000000..0c714c6 --- /dev/null +++ b/tuya/device.py @@ -0,0 +1,139 @@ +import tinytuya +import requests +import time + +def get_value_safely(data, key): + try: + # Tente d'obtenir la valeur associée à la clé, si elle existe + value = data['dps'].get(key, None) + + # Si la valeur est None, renvoie 0 + return value if value is not None else 0 + + except Exception as e: + # En cas d'erreur, imprime un message d'erreur et renvoie 0 + print(f"Erreur : {e}") + return 0 + +# Connect to Device + #"apiKey": "hgkvdyrstyhqudku3xdu", + #"apiSecret": "704a1bad394a4efe805f46fb04c46916", + #"apiRegion": "eu-w", + #"apiDeviceID": "bf4d021ef10d39ea17gpwo" + +response = "" +while True: + d = tinytuya.OutletDevice( + dev_id='bf4d021ef10d39ea17gpwo', + address='192.168.1.15', # 53 Or set to 'Auto' to auto-discover IP address + local_key='4.p}ZHi*hO>wVFl-', + version=3.5) + + # Get Status + data = d.status() + print('set_status() result %r' % data) + + #data = json.loads(data) + + # Utilisation de la fonction get_value_safely pour remplacer les lignes existantes + value_105 = get_value_safely(data, '105') + value_106 = get_value_safely(data, '106') + value_107 = get_value_safely(data, '107') + value_108 = get_value_safely(data, '108') or 0 + value_109 = get_value_safely(data, '109') or 0 + value_115 = get_value_safely(data, '115') + value_116 = get_value_safely(data, '116') + value_117 = get_value_safely(data, '117') + value_118 = get_value_safely(data, '118') or 0 + value_119 = get_value_safely(data, '119') or 0 + + # Afficher les valeurs + print("=================================") + #print("103 :", data['dps'].get('103', None) or 0) + #print("104 :", data['dps'].get('104', None) or 0) + print("105 Valeur watt :", value_105 / 10) + print("106 Valeur mA :", value_106) + print("107 Valeur Volt :", value_107 / 10) + print("108 Cumul kWh :", value_108 / 1000) + print("109 Valeur kWh :", value_109 / 1000) + #print("110 :", data['dps'].get('110', None)) + #print("111 Alerte 1 :", data['dps'].get('111', None)) + print("=================================") + #print("113 :", data['dps'].get('113', None)) + #print("114 :", data['dps'].get('114', None)) + print("115 Valeur watt :", value_115 / 10) + print("116 Valeur mA :", value_116) + print("117 Valeur Volt :", value_117 / 10) + print("118 Cumul kWh :", value_118 / 1000) + print("119 Valeur kWh :", value_119 / 1000) + #print("120 :", data['dps'].get('120', None)) + #print("121 Alerte 2 :", data['dps'].get('121', None)) + print("=================================") + + #print("122 :", data['dps'].get('122', None)) + #print("123 :", data['dps'].get('123', None)) + #print("124 :", data['dps'].get('124', None)) + # Turn On + #d.turn_on() + + # id domoticz 1181 + # print('1121|0|' + str(value_105) + ";0;" + str(value_115) + ";0;" + str(value_108) + ";" + str(value_118)) + + # Effectuer une requête GET + #url = "http://192.168.1.3:81/json.htm?type=command¶m=udevice&idx=1181&nvalue=0&svalue=" + str(value_109) + ";" + str(value_105 / 10) + ";" + str(value_119) + ";" + str(value_115 / 10) + ";;" + url = "http://192.168.1.3:81/json.htm?type=command¶m=udevice&idx=1181&nvalue=0&svalue=" + str(value_109) + ";0;" + str(value_119) + ";0;" + str(value_105 / 10) + ";" + str(value_115 / 10) #USAGE1;USAGE2;RETURN1;RETURN2;CONS;PROD + + #USAGE1;USAGE2;RETURN1;RETURN2;CONS;PROD + print(url) + try: + response = requests.get(url) + print(response) + except requests.RequestException as e: + # Gérez les autres erreurs liées aux requêtes ici + print(f"Erreur de requête : {e}") + + time.sleep(1) + + + # 1185 Radiateur + idx = "1185" + url = "http://192.168.1.3:81/json.htm?type=command¶m=udevice&idx=" + idx + "&svalue=" + str(value_115 / 10) + ";0&nvalue=0"; + try: + response = requests.get(url) + print(response) + except requests.RequestException as e: + # Gérez les autres erreurs liées aux requêtes ici + print(f"Erreur de requête : {e}") + print(response) + time.sleep(1) + + # 1184 Chauffe eau 2 + idx = "1184" + url = "http://192.168.1.3:81/json.htm?type=command¶m=udevice&idx=" + idx + "&svalue=" + str(value_105 / 10) + ";0&nvalue=0"; + try: + response = requests.get(url) + print(response) + except requests.RequestException as e: + # Gérez les autres erreurs liées aux requêtes ici + print(f"Erreur de requête : {e}") + + # --USAGE1= energy usage meter tariff 1, This is an incrementing counter + # --USAGE2= energy usage meter tariff 2, This is an incrementing counter + # --RETURN1= energy return meter tariff 1, This is an incrementing counter + # --RETURN2= energy return meter tariff 2, This is an incrementing counter + # --CONS= actual usage power (Watt) + # --PROD= actual return power (Watt) + # .. tostring(math.floor(watt_p1)) .. ';' + # .. tostring(math.floor(watt_p2)) .. ';' + # -- + value_solar2 - counter_solar2 + # .. tostring(math.floor(value_solar - counter_solar + value_solar2 - counter_solar2)) .. ';' + # .. '0;' + # .. tostring(math.floor(math.max(0,watt) + watt_solaire)).. ';' + # .. tostring(math.floor(watt_solaire)) --math.floor(ConsumoEnergyBalance / 1000)) --round(watt,0)) + + + # Turn Off + #d.turn_off() + time.sleep(25) + + diff --git a/tuya/device2.py b/tuya/device2.py new file mode 100644 index 0000000..dd9d782 --- /dev/null +++ b/tuya/device2.py @@ -0,0 +1,248 @@ +import tinytuya +import requests +import time +import math +import numpy as np +from scipy import stats + +from datetime import datetime + +def get_value_safely(data, key): + try: + # Tente d'obtenir la valeur associée à la clé, si elle existe + value = data['dps'].get(key, None) + + # Si la valeur est None, renvoie 0 + return value if value is not None else 0 + + except Exception as e: + # En cas d'erreur, imprime un message d'erreur et renvoie 0 + print(f"Erreur : {e}") + return 0 + +# Obtenir la date et l'heure actuelles +maintenant = datetime.now() + +# Formater la date et l'heure +format_date_heure = maintenant.strftime("%Y-%m-%d %H:%M:%S") + +# Imprimer la date et l'heure +print("Date et Heure actuelles :", format_date_heure) + + +# Connect to Device + #"apiKey": "hgkvdyrstyhqudku3xdu", + #"apiSecret": "704a1bad394a4efe805f46fb04c46916", + #"apiRegion": "eu-w", + #"apiDeviceID": "bf4d021ef10d39ea17gpwo" + +response = "" +previous_sens = "" +watt_1_p = 0 +watt_2_p = 0 +PUISSANCE_DELESTAGE = 750 # Watts +MAX_VALUES = 5 + +# Initialisation de la liste des dernières valeurs +last_values = [] + +# Initialisation de la somme des valeurs +sum_values = 0 + +# Initialisation du compteur pour suivre le nombre de valeurs ajoutées +counter = 0 + + +def remove_outliers(values): + if len(values) < 2: + return values + z_scores = stats.zscore(values) + abs_z_scores = np.abs(z_scores) + filtered_entries = (abs_z_scores < 3) + return values[filtered_entries] + +while True: + d = tinytuya.OutletDevice( + dev_id='bf9109f5435d9bb3c6avlr', + address='192.168.1.14', # Or set to 'Auto' to auto-discover IP address + local_key='/Pht&M$(/nt@t}qV', + version=3.4) + # Get Status + data = d.status() + print('set_status() result %r' % data) + + #data = json.loads(data) + # for key, value in data['dps'].items(): + # print(f'{key.ljust(5)}: {str(value).ljust(10)}') + + + # Extraire les valeurs des champs spécifiques + #total = data['dps'].get('115', None) / 10 + # Utilisation de la fonction get_value_safely pour remplacer les lignes existantes + total_1 = get_value_safely(data, '1') + total_2 = get_value_safely(data, '2') + volt_1 = get_value_safely(data, '112') / 10 or 0 + freq_1 = get_value_safely(data, '111') / 100 or 0 + current_1 = get_value_safely(data, '113') or 0 + factor_1 = get_value_safely(data, '110') / 100 or 0 + prod_1 = get_value_safely(data, '107') or 0 + + watt_1 = get_value_safely(data, '101') / 10 or 0 + watt_2 = get_value_safely(data, '105') / 10 or 0 + prod_2 = get_value_safely(data, '108') or 0 + current_2 = get_value_safely(data, '114') or 0 + sens_1 = get_value_safely(data, '102') + sens_2 = get_value_safely(data, '104') + + value_106 = get_value_safely(data, '106') or 0 + value_109 = get_value_safely(data, '109') or 0 + + + # Afficher les valeurs + print("=================================") + print("1 kWh :", total_1 ) + print("2 kWh :", total_2 ) + # print("101 total :", total_1) + print("101 Watt 1 :", watt_1) + print("105 Watt 2 :", watt_2) + print("102 Sens 1 :", sens_1) + print("104 Sens 2 :", sens_2) + + print("106 conso jour 1:", value_106) + print("107 prod jour 1 :", prod_1) + print("108 conso jour 2:", prod_2) + print("109 prod jour 2:", value_109) + print("110 factor :", factor_1) + print("111 freq :", freq_1) + print("112 Volt :", volt_1) + print("113 Current 1 :", current_1) + print("114 Current 2 :", current_2) + #print("115 :", value_115 / 10) + print("=================================") + # Turn On + #d.turn_on() + #if (sens_1 == "FORWARD" and watt_1 > watt_2 - 100): + # sens_1 = "NORMAL" + if (watt_1 == 0 and watt_2 == 0): + time.sleep(10) + continue + if (watt_1 == watt_1_p and watt_2 == watt_2_p): + time.sleep(10) + continue + + watt_1_p = watt_1 + watt_2_p = watt_2 + if (sens_1 != previous_sens): + previous_sens = sens_1 + time.sleep(15) + continue + previous_sens = sens_1 + + # id domoticz 1181 + # print('1121|0|' + str(value_105) + ";0;" + str(value_115) + ";0;" + str(value_108) + ";" + str(value_118)) + #if sens_1 == "REVERSE": + # watt_1 = 0 + + # 1087 Solaire production + solaire = watt_2 if watt_2 > 0 else 0 + + if watt_1 < 0 and solaire < - watt_1 + 90: + time.sleep(15) + continue + + value = (watt_1 if sens_1 == "FORWARD" else - watt_1) + + # Tuya Device 2 + url = "http://192.168.1.3:81/json.htm?type=command¶m=udevice&idx=1182&nvalue=0&svalue=" + str(total_1) + ";0;" + str(total_2) + ";0;" + str(watt_1) + ";" + str(solaire) #USAGE1;USAGE2;RETURN1;RETURN2;CONS;PROD + if watt_1 or watt_2: + print(url) + try: + response = requests.get(url) + print(response) + except requests.RequestException as e: + # Gérez les autres erreurs liées aux requêtes ici + print(f"Erreur de requête : {e}") + time.sleep(1) + + + + #value=moyenne + idx = "1087" + url = "http://192.168.1.3:81/json.htm?type=command¶m=udevice&idx=" + idx + "&svalue=" + str(solaire) + ";0&nvalue=0"; + #response = requests.get(url) + #print(response) + time.sleep(1) + + + # 1123 Consommation_Apparente + last_values.append(value) + sum_values += value + counter += 1 + # Vérifier si la liste des dernières valeurs dépasse éléments + if len(last_values) > MAX_VALUES: + # Si oui, retirer la première valeur de la liste et ajuster la somme + sum_values -= last_values.pop(0) + + # Calculer la moyenne des dernières valeurs + print(f"Valeurs non filtrées : {last_values}") + # Convertir en numpy array pour le filtrage + #last_values_np = np.array(last_values) + + # Enlever les valeurs aberrantes + #last_values_np = remove_outliers(last_values_np) + + # Convertir le résultat filtré en liste et mettre à jour last_values + #last_values = list(last_values_np) + + print(f"Valeurs filtrées (sans aberrantes): {last_values}") + + moyenne = sum_values / min(counter, MAX_VALUES) + #value=moyenne + #watt_1=moyenne + + # Utiliser la moyenne comme vous le souhaitez (par exemple, l'afficher) + print("Moyenne des dernières valeurs :", moyenne) + + + if 1 == 1: #(sens_1 == previous_sens): + #if value < 0 and (abs(value) > watt_2): + # value = -value + #if value < 0 and abs(value) > solaire - 100: + # time.sleep(3) + # continue + idx = "1123" + url = "http://192.168.1.3:81/json.htm?type=command¶m=udevice&idx=" + idx + "&svalue=" + str(value) + ";0&nvalue=0"; + try: + response = requests.get(url) + print(response) + except requests.RequestException as e: + # Gérez les autres erreurs liées aux requêtes ici + print(f"Erreur de requête : {e}") + + time.sleep(1) + + # 1138 Mesure Courant + idx = "1138" + url = "http://192.168.1.3:81/json.htm?type=command¶m=udevice&idx=" + idx + "&svalue=" + str(watt_2) + ";0&nvalue=0"; + try: + response = requests.get(url) + print(response) + except requests.RequestException as e: + # Gérez les autres erreurs liées aux requêtes ici + print(f"Erreur de requête : {e}") + + time.sleep(1) + + + # 1115 CONSOMMATION_GENERALE + idx = "1115" + url = "http://192.168.1.3:81/json.htm?type=command¶m=udevice&idx=" + idx + "&svalue=" + str(watt_1) + ";0&nvalue=0"; + try: + #response = requests.get(url) + print(response) + except requests.RequestException as e: + # Gérez les autres erreurs liées aux requêtes ici + print(f"Erreur de requête : {e}") + previous_sens = sens_1 + time.sleep(5) + diff --git a/tuya/devices.json b/tuya/devices.json new file mode 100644 index 0000000..350d463 --- /dev/null +++ b/tuya/devices.json @@ -0,0 +1,20 @@ +[ + { + "name": "Double Digital Meter", + "id": "bf4d021ef10d39ea17gpwo", + "key": "4.p}ZHi*hO>wVFl-", + "mac": "c4:82:e1:d1:61:71", + "uuid": "bdc119a10da28a03", + "sn": "YHLD-14500023", + "category": "cz", + "product_name": "Double Digital Meter", + "product_id": "79a7z01v3n35kytb", + "biz_type": 0, + "model": "", + "sub": false, + "icon": "https://images.tuyaeu.com/smart/icon/ay1504535816017oOfFp/3ccdd6937c07d34f2ee22721b4aa1247.jpg", + "mapping": {}, + "ip": "192.168.1.53", + "version": "3.5" + } +] \ No newline at end of file diff --git a/tuya/energie.sh b/tuya/energie.sh new file mode 100755 index 0000000..660c834 --- /dev/null +++ b/tuya/energie.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +for i in {1..10} +do + /usr/bin/python3 /opt/domoticz/scripts/tuya/device.py + #/usr/bin/python3 /opt/domoticz/scripts/tuya/device2.py + sleep 5 +done + diff --git a/tuya/micro.py b/tuya/micro.py new file mode 100644 index 0000000..1d44580 --- /dev/null +++ b/tuya/micro.py @@ -0,0 +1,67 @@ +from flask import Flask, request +import tinytuya + +app = Flask(__name__) + +def get_value_safely(data, key): + try: + # Tente d'obtenir la valeur associée à la clé, si elle existe + value = data['dps'].get(key, None) + + # Si la valeur est None, renvoie 0 + return value if value is not None else 0 + + except Exception as e: + # En cas d'erreur, imprime un message d'erreur et renvoie 0 + print(f"Erreur : {e}") + return 0 + +@app.route('/control', methods=['POST']) +def control_device(): + action = request.json.get('action') + device_id = 'bf9109f5435d9bb3c6avlr' + local_key = '/Pht&M$(/nt@t}qV' + ip_address = '192.168.1.14' + + d = tinytuya.OutletDevice(dev_id=device_id, address=ip_address, local_key=local_key, version=3.4) + d.set_version(3.4) # Set the version of Tuya protocol + +# if action == 'on': +# d.turn_on() +# elif action == 'off': +# d.turn_off() + data = d.status() + print('set_status() result %r' % data) + + #data = json.loads(data) + # for key, value in data['dps'].items(): + # print(f'{key.ljust(5)}: {str(value).ljust(10)}') + + + # Extraire les valeurs des champs spécifiques + #total = data['dps'].get('115', None) / 10 + # Utilisation de la fonction get_value_safely pour remplacer les lignes existantes + total_1 = get_value_safely(data, '1') + total_2 = get_value_safely(data, '2') + volt_1 = get_value_safely(data, '112') / 10 or 0 + freq_1 = get_value_safely(data, '111') / 100 or 0 + current_1 = get_value_safely(data, '113') or 0 + factor_1 = get_value_safely(data, '110') / 100 or 0 + prod_1 = get_value_safely(data, '107') or 0 + + watt_1 = get_value_safely(data, '101') / 10 or 0 + watt_2 = get_value_safely(data, '105') / 10 or 0 + prod_2 = get_value_safely(data, '108') or 0 + current_2 = get_value_safely(data, '114') or 0 + sens_1 = get_value_safely(data, '102') + sens_2 = get_value_safely(data, '104') + + value_106 = get_value_safely(data, '106') or 0 + value_109 = get_value_safely(data, '109') or 0 + + + return {"conso_apparente": (watt_1 if sens_1 == "FORWARD" else - watt_1), "production": watt_2 if watt_2 > 0 else 0 } + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000) + diff --git a/tuya/snapshot.json b/tuya/snapshot.json new file mode 100644 index 0000000..46ec150 --- /dev/null +++ b/tuya/snapshot.json @@ -0,0 +1,24 @@ +{ + "timestamp": 1710608212.8361237, + "devices": [ + { + "id": "bf4d021ef10d39ea17gpwo", + "name": "Double Digital Meter", + "key": "4.p}ZHi*hO>wVFl-", + "mac": "c4:82:e1:d1:61:71", + "uuid": "bdc119a10da28a03", + "sn": "YHLD-14500023", + "category": "cz", + "product_name": "Double Digital Meter", + "product_id": "79a7z01v3n35kytb", + "biz_type": 0, + "model": "", + "sub": false, + "icon": "https://images.tuyaeu.com/smart/icon/ay1504535816017oOfFp/3ccdd6937c07d34f2ee22721b4aa1247.jpg", + "mapping": {}, + "ip": "", + "origin": "cloud", + "ver": "3.5" + } + ] +} \ No newline at end of file diff --git a/tuya/test.py b/tuya/test.py new file mode 100644 index 0000000..665a5b8 --- /dev/null +++ b/tuya/test.py @@ -0,0 +1,46 @@ +import time +import numpy as np + +def get_dynamic_values(): + # Simule la récupération des valeurs dynamiques. + # Par exemple, elle pourrait lire des valeurs depuis un capteur ou une API. + # Pour cet exemple, nous allons générer une valeur aléatoire. + return np.random.normal(loc=50, scale=10) # Valeur aléatoire avec une moyenne de 50 et un écart-type de 10 + +def update_values(values, new_value, threshold=3): + if len(values) == 0: + return [new_value] + + old_mean = np.mean(values) + + # Ajouter la nouvelle valeur et retirer la première valeur (si nécessaire) + if len(values) >= 10: # par exemple, une fenêtre de 10 valeurs + values.pop(0) + + values.append(new_value) + + new_mean = np.mean(values) + + # Vérifier si la nouvelle valeur change significativement la moyenne + if abs(new_mean - old_mean) > threshold: + return values # Accepter la nouvelle valeur + else: + values.pop() # Rejeter la nouvelle valeur + return values + +# Tableau pour stocker les dernières valeurs +last_values = [] + +# Boucle principale +while True: + new_value = get_dynamic_values() + print(f"Nouvelle valeur récupérée: {new_value}") + + # Mettre à jour les valeurs avec la nouvelle valeur + last_values = update_values(last_values, new_value) + + print(f"Valeurs mises à jour: {last_values}") + + # Attendre 5 secondes avant de récupérer la nouvelle valeur + time.sleep(1) + diff --git a/tuya/test2.py b/tuya/test2.py new file mode 100644 index 0000000..747f231 --- /dev/null +++ b/tuya/test2.py @@ -0,0 +1,57 @@ +import numpy as np + +def get_dynamic_values(): + # Simule la récupération des valeurs dynamiques. + return np.random.normal(loc=50, scale=10) # Valeur aléatoire avec une moyenne de 50 et un écart-type de 10 + +def update_values(values, new_value, rejected_values, threshold=10): + if len(values) == 0: + return [new_value], rejected_values + + old_mean = np.mean(values) # Calcul de la moyenne actuelle + print(f"Ancienne moyenne: {old_mean}") + + if new_value in rejected_values: + # Si la nouvelle valeur a été rejetée précédemment, l'accepter maintenant + values.append(new_value) + rejected_values.remove(new_value) + print(f"Valeur {new_value} acceptée après rejet initial") + else: + # Ajouter la nouvelle valeur et retirer la première valeur (si nécessaire) + if len(values) >= 10: # par exemple, une fenêtre de 10 valeurs + values.pop(0) + + values.append(new_value) + + new_mean = np.mean(values) # Calcul de la nouvelle moyenne + print(f"Nouvelle moyenne avec la nouvelle valeur: {new_mean}") + + # Vérifier si la nouvelle valeur change significativement la moyenne + difference = abs(new_mean - old_mean) + print(f"Différence entre les moyennes: {difference}") + + if difference > threshold: + # Rejeter temporairement la nouvelle valeur + rejected_values.add(new_value) + values.pop() # Retirer la nouvelle valeur + print(f"Valeur {new_value} rejetée temporairement") + else: + print(f"Valeur {new_value} acceptée") + + return values, rejected_values + +# Tableau pour stocker les dernières valeurs +last_values = [10, 10, 10] +rejected_values = set() + +# Nouvelles valeurs à recevoir +new_values = [30, 30] + +for new_value in new_values: + print(f"Nouvelle valeur récupérée: {new_value}") + last_values, rejected_values = update_values(last_values, new_value, rejected_values) + print(f"Valeurs mises à jour: {last_values}\n") + +# Afficher le tableau final +print(f"Tableau final des valeurs: {last_values}") + diff --git a/tuya/tinytuya b/tuya/tinytuya new file mode 160000 index 0000000..879d896 --- /dev/null +++ b/tuya/tinytuya @@ -0,0 +1 @@ +Subproject commit 879d896e74798e059e898eebe0917290a878f5f6 diff --git a/tuya/tinytuya.json b/tuya/tinytuya.json new file mode 100644 index 0000000..85a4fbd --- /dev/null +++ b/tuya/tinytuya.json @@ -0,0 +1,6 @@ +{ + "apiKey": "dprdvq43qxca8e4nres7", + "apiSecret": "fb14e8b28fde462886ca19e05351773b", + "apiRegion": "eu", + "apiDeviceID": "scan" +} \ No newline at end of file diff --git a/tuya/tinytuya.old b/tuya/tinytuya.old new file mode 100644 index 0000000..ee66f6d --- /dev/null +++ b/tuya/tinytuya.old @@ -0,0 +1,6 @@ +{ + "apiKey": "hgkvdyrstyhqudku3xdu", + "apiSecret": "704a1bad394a4efe805f46fb04c46916", + "apiRegion": "eu-w", + "apiDeviceID": "bf4d021ef10d39ea17gpwo" +} \ No newline at end of file diff --git a/tuya/tuya-raw.json b/tuya/tuya-raw.json new file mode 100644 index 0000000..6481752 --- /dev/null +++ b/tuya/tuya-raw.json @@ -0,0 +1,39 @@ +{ + "result": [ + { + "active_time": 1707412318, + "biz_type": 0, + "category": "cz", + "create_time": 1707412318, + "icon": "smart/icon/ay1504535816017oOfFp/3ccdd6937c07d34f2ee22721b4aa1247.jpg", + "id": "bf4d021ef10d39ea17gpwo", + "ip": "92.139.36.216", + "lat": "47.7300", + "local_key": "4.p}ZHi*hO>wVFl-", + "lon": "-2.1299", + "model": "", + "name": "Double Digital Meter", + "online": true, + "owner_id": "77373556", + "product_id": "79a7z01v3n35kytb", + "product_name": "Double Digital Meter", + "status": [], + "sub": false, + "time_zone": "+01:00", + "uid": "eu1672858188675Mwj0l", + "update_time": 1707415198, + "uuid": "bdc119a10da28a03", + "mapping": {} + } + ], + "success": true, + "t": 1707417101936, + "tid": "4de5774cc6b011eeb4228e673063ebcd", + "file": { + "name": "tuya-raw.json", + "description": "Full raw list of Tuya devices.", + "account": "dprdvq43qxca8e4nres7", + "date": "2024-02-08T19:31:42.313408", + "tinytuya": "1.13.1" + } +} \ No newline at end of file diff --git a/underground.sh b/underground.sh new file mode 100755 index 0000000..6a769b4 --- /dev/null +++ b/underground.sh @@ -0,0 +1,88 @@ +#!/bin/bash +#Rapatriement des valeurs depuis api.wunderground.com +#D�finition des param�tres de base +apikey=48a08328a93a18a1 +#pwsid=pws:ILAGACIL2 #trouver le votre sur https://www.wunderground.com/ +#pwsid=pws:IBRITTAN2 +pwsid=pws:ISAINTGR13 +# A adapter selon que vous ayez param�tr� une authentification +IPDomoticz=localhost:81 +#IPDomoticz=username:password@192.168.x.y:8080 + +# D�claration des idx des devices cr��s +idxTempHumBar=94 +idxVent=95 +idxPluie=305 +idxVisi=97 +idxUV=99 +idxHum=332 + +########################## NE RIEN MODIFIER EN DESSOUS DE CETTE LIGNE ############################### +#R�cup�ration des donn�es et isolement des variables temp/relative_hum/pressure_mb +#curl -s http://api.wunderground.com/api/48a08328a93a18a1/conditions/q/pws:ISAINTGR13.json? + +capture=`curl -s http://api.wunderground.com/api/$apikey/conditions/q/$pwsid.json? | grep -E 'temp_c|relative_humidity|wind_dir|wind_degrees|wind_kph|wind_gust_kph|pressure_mb|feelslike_c|visibility_km|UV|precip_1hr_metric|precip_today_metric' | cut -d ':' -f 2 | tr -d '"' | tr -d ','` + +#D�composition des �l�ments +TEMP=`echo $capture | cut -d ' ' -f 1` +HUM=`echo $capture | cut -d ' ' -f 2 | cut -d '%' -f 1` +WD=`echo $capture | cut -d ' ' -f 3` +WB=`echo $capture | cut -d ' ' -f 4` +WS=`echo $capture | cut -d ' ' -f 5` +WG=`echo $capture | cut -d ' ' -f 6` +BAR=`echo $capture | cut -d ' ' -f 7` +TEMP_R=`echo $capture | cut -d ' ' -f 8` +VISIBILITE=`echo $capture | cut -d ' ' -f 9` +UV=`echo $capture | cut -d ' ' -f 10` +PLUIE_1H=`echo $capture | cut -d ' ' -f 11` +PLUIE_TOTAL=`echo $capture | cut -d ' ' -f 12` + +echo "La temp�rature est de : "$TEMP" �C" +echo "L'humidit� relative est de : "$HUM" %" +echo "La pression atmosph�rique est de : "$BAR" hPa" +echo "Le vent vient de "$WD" � une vitesse moyenne de "$WS" km/h avec des rafales � "$WG" km/h" +echo "La temp�rature ressentie est de : "$TEMP_R" �C" +echo "La visibilité est de : "$VISIBILITE" C" + +#Humidit� relative : indicatif de confort (pourcentage) +# 00-040 : sec +# 40-065 : confortable +# 65-100 : humide +if [ "$HUM" -lt 40 ]; then + HUM_STAT="2" +elif [ "$HUM" -lt 65 ]; then + HUM_STAT="1" + else HUM_STAT="3" +fi +# Affichage du r�sultat +echo $HUM_STAT + +#Pression atmosph�rique : tendance m�t�orologique +# <1000 hPa : Pluie "4" +# 1000-1010 hPa : Nuageux "3" +# 1010-1010 hPa : Partiellement nuageux "2" +# >1020 hPa : Ensoleill� "1" + +if [ "$BAR" -lt 1000 ]; then + BAR_STAT="4" +elif [ "$BAR" -lt 1010 ]; then + BAR_STAT="3" + elif [ "$BAR" -lt 1020 ]; then + BAR_STAT="2" + else BAR_STAT="1" +fi +# Affichage du r�sultat +echo $BAR_STAT + +#Mise � jour du capteur TempHumBar +curl -s "http://"$IPDomoticz"/json.htm?type=command¶m=udevice&idx="$idxTempHumBar"&nvalue=0&svalue="$TEMP";"$HUM";"$HUM_STAT";"$BAR";"$BAR_STAT +#Mise � jour du capteur Vent +curl -s "http://"$IPDomoticz"/json.htm?type=command¶m=udevice&idx="$idxVent"&nvalue=0&svalue="$WB";"$WD";"$WS";"$WG";"$TEMP";"$TEMP_R +#Mise � jour du capteur Pluie +curl -s "http://"$IPDomoticz"/json.htm?type=command¶m=udevice&idx="$idxPluie"&nvalue=0&svalue="$PLUIE_1H";"$PLUIE_TOTAL +#Mise � jour du visibilité +curl -s "http://"$IPDomoticz"/json.htm?type=command¶m=udevice&idx="$idxVisi"&nvalue=0&svalue="$VISIBILITE";0" #$VISIBILITE +#Mise � jour de UV +curl -s "http://"$IPDomoticz"/json.htm?type=command¶m=udevice&idx="$idxUV"&nvalue=0&svalue="$UV";0" +#Mise a jour de humidit� +curl -s "http://"$IPDomoticz"/json.htm?type=command¶m=udevice&idx="$idxHum"&nvalue="$HUM"&svalue="$HUM_STAT diff --git a/update.sh b/update.sh new file mode 100755 index 0000000..f1bf51d --- /dev/null +++ b/update.sh @@ -0,0 +1,55 @@ +#!/bin/sh + +cd /home/souti/dev-domoticz/ +# This script can be used to upgrade/compile to the latest version +# Please not that all modifications on the original files are lost + +echo "Updating to server revision..." + +json="http://localhost:81/json.htm?type=command¶m=udevice&idx=89&nvalue=3&svalue=Update_en_cours" +#echo "HUM " $json >>/var/log/syslog +curl -s -i -H "Accept: application/json" $json >/dev/null 2>>/var/log/syslog + +git fetch --all +if [ $? -ne 0 ] +then + json="http://localhost:81/json.htm?type=command¶m=udevice&idx=89&nvalue=4&svalue=Git_a_echoue" + #echo "HUM " $json >>/var/log/syslog + curl -s -i -H "Accept: application/json" $json >/dev/null 2>>/var/log/syslog + exit 1 +fi +git reset --hard origin/master + +json="http://localhost:81/json.htm?type=command¶m=udevice&idx=89&nvalue=3&svalue=Fetch_Git_Termine" +#echo "HUM " $json >>/var/log/syslog +curl -s -i -H "Accept: application/json" $json >/dev/null 2>>/var/log/syslog + +cmake -DCMAKE_BUILD_TYPE=Release . +if [ $? -ne 0 ] +then + echo "CMake failed!"; + json="http://localhost:81/json.htm?type=command¶m=udevice&idx=89&nvalue=4&svalue=CMake_a_echoue" + #echo "HUM " $json >>/var/log/syslog + curl -s -i -H "Accept: application/json" $json >/dev/null 2>>/var/log/syslog + exit 1 +fi + +json="http://localhost:81/json.htm?type=command¶m=udevice&idx=89&nvalue=2&svalue=Compilation_en_cours" +#echo "HUM " $json >>/var/log/syslog +curl -s -i -H "Accept: application/json" $json >/dev/null 2>>/var/log/syslog +make +if [ $? -ne 0 ] +then + echo "Compile failed!"; + json="http://localhost:81/json.htm?type=command¶m=udevice&idx=89&nvalue=3&svalue=Compilation_a_echoue" + #echo "HUM " $json >>/var/log/syslog + curl -s -i -H "Accept: application/json" $json >/dev/null 2>>/var/log/syslog + exit 1 +fi +# Restart domoticz +#echo "Restarting Domoticz... (please standby...)" +#sudo service domoticz.sh restart +version=`cat appversion.h |grep APPVERSION |awk -F " " '{print $3}'` +json="http://localhost:81/json.htm?type=command¶m=udevice&idx=89&nvalue=1&svalue=Nouvelle_version_disponible_$version" +#echo "HUM " $json >>/var/log/syslog +curl -s -i -H "Accept: application/json" $json >/dev/null 2>>/var/log/syslog diff --git a/update_domoticz b/update_domoticz new file mode 100755 index 0000000..8835685 --- /dev/null +++ b/update_domoticz @@ -0,0 +1,28 @@ +#!/bin/sh +cd $1 + +tar xfz update.tgz +rm update.tgz +rm update.tgz.sha256sum + +lowercase(){ + echo "$1" | sed "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/" +} + +OS=`lowercase \`uname -s\`` +MACH=`uname -m` + +# Restart on OSX +if [ ${OS} = "darwin" ]; then + launchctl unload /System/Library/LaunchAgents/com.domoticz.server.plist + echo "Please standby ..." + sleep 2 + launchctl load /System/Library/LaunchAgents/com.domoticz.server.plist +else + sudo service domoticz.sh stop + sudo systemctl stop domoticz.service + echo "Please standby ..." + sleep 2 + sudo service domoticz.sh start + sudo systemctl start domoticz.service +fi diff --git a/vacancesOff.sh b/vacancesOff.sh new file mode 100755 index 0000000..33ca894 --- /dev/null +++ b/vacancesOff.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +echo "Vacances Off" >>/tmp/log diff --git a/vacancesOn.sh b/vacancesOn.sh new file mode 100755 index 0000000..36dd94c --- /dev/null +++ b/vacancesOn.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +echo "Vacances On" >>/tmp/log diff --git a/vnc.sh b/vnc.sh new file mode 100755 index 0000000..9077e09 --- /dev/null +++ b/vnc.sh @@ -0,0 +1,2 @@ +#!/bin/bash +/usr/bin/x11vnc -forever -noxdamage -repeat -rfbport 5900 -shared -display :0 diff --git a/vol b/vol new file mode 100755 index 0000000..05b4cf0 --- /dev/null +++ b/vol @@ -0,0 +1,82 @@ +#!/bin/bash + +MIX=amixer +declare -i LO=0 # Minimum volume; try 10 to avoid complete silence +declare -i HI=100 # Maximum volume; try 95 to avoid distortion +declare -i ADJ=3 # Volume adjustment step size + +usage () +{ + echo "Usage: `basename $0` [ - | + | N ]" >&2 + echo " where N is a whole number between $LO and $HI, inclusive." >&2 + exit 1 +} + +# Zero or one argument +[ $# -le 1 ] || usage + +# Argument must be one of: empty, -, +, number +[[ $1 == ?(-|+|+([0-9])) ]] || usage + +ARG="$1" + +# Number argument +if [[ $ARG == +([0-9]) ]]; then + # Strip leading zeros + while [[ $ARG == 0+([0-9]) ]]; do + ARG=${ARG#0} + done + # Must be between LO and HI + (( ARG >= LO && ARG <= HI )) || usage +fi + +EXE=$(which $MIX) +if [ -z "$EXE" ]; then + echo "Error: $MIX not found. Try \"sudo apt-get install alsa-utils\" first." >&2 + exit 2 +fi + +GET=$($EXE cget numid=1) +declare -i MIN=-4000 +#declare -i MIN=$(echo $GET | /bin/grep -E -o -e ',min=[^,]+' | /bin/grep -E -o -e '[0-9-]+') +declare -i MAX=$(echo $GET | /bin/grep -E -o -e ',max=[^,]+' | /bin/grep -E -o -e '[0-9-]+') +declare -i VAL=$(echo $GET | /bin/grep -E -o -e ': values=[0-9+-]+' | /bin/grep -E -o -e '[0-9-]+') + +echo $MIN $MAX $VAL + +if (( MIN >= MAX || VAL < MIN || VAL > MAX )); then + echo "Error: could not get the right values from $MIX output." >&2 + exit 3 +fi + +declare -i LEN=0 +(( LEN = MAX - MIN )) + +declare -i ABS=0 +(( ABS = VAL - MIN )) + +declare -i PCT=0 +(( PCT = 100 * ABS / LEN )) + +if [ ! -z "$ARG" ]; then + + declare -i OLD=$PCT + + if [[ "$ARG" == "+" ]]; then + (( PCT += ADJ )) + elif [[ "$ARG" == "-" ]]; then + (( PCT -= ADJ )) + else + PCT=$ARG + fi + + if [[ "$PCT" != "$OLD" ]]; then + (( ABS = PCT * LEN / 100 )) + (( VAL = MIN + ABS )) + $EXE -q cset numid=1 -- $VAL + fi +fi + +echo $PCT +exit 0 + diff --git a/voletOff.sh b/voletOff.sh new file mode 100755 index 0000000..5f63ac7 --- /dev/null +++ b/voletOff.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +echo "Volet Off" >>/tmp/log diff --git a/voletOn.sh b/voletOn.sh new file mode 100755 index 0000000..63d9e78 --- /dev/null +++ b/voletOn.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +echo "Volets On" >>/tmp/log diff --git a/voletVelux.sh b/voletVelux.sh new file mode 100755 index 0000000..8bf3179 --- /dev/null +++ b/voletVelux.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +lockfile-create "/tmp/voletVelux.lockfile" + + +#curl "http://192.168.1.35/$1?speed=$2" +#sleep $3 +#curl "http://192.168.1.35/stop" + +curl "http://192.168.1.41/$1?time=$3" +#sleep $3 +#curl "http://192.168.1.40/stop" +lockfile-remove "/tmp/voletVelux.lockfile" + diff --git a/volets.sh b/volets.sh new file mode 100755 index 0000000..d0cf083 --- /dev/null +++ b/volets.sh @@ -0,0 +1,48 @@ +#!/bin/bash + DOMO_IP="localhost" # Domoticz IP Address + DOMO_PORT="81" # Domoticz Port + Gauche_IDX=684 # numéro ID de l interrupteur du relais + Droit_IDX=701 + Milieu_IDX=699 + duree=10 + +lockfile-create "/tmp/volet.lockfile" + +echo "Avant $1" >>/tmp/test +curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$Droit_IDX&switchcmd=$1" & +sleep $duree +curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$Droit_IDX&switchcmd=$1" & +sleep 2 +curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$Milieu_IDX&switchcmd=$1" & +sleep $duree +curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$Milieu_IDX&switchcmd=$1" & +sleep 2 +curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$Gauche_IDX&switchcmd=$1" & +sleep $duree +curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$Gauche_IDX&switchcmd=$1" & + +if [ "$1" = "On" ] +then + mosquitto_pub -t "jerome.delacotte@gmail.com/chambre/volet" -m "d" + sleep 1 + mosquitto_pub -t "jerome.delacotte@gmail.com/theo/volet" -m "d" + sleep 1 + mosquitto_pub -t "jerome.delacotte@gmail.com/manon/volet" -m "d" + sleep 6 + mosquitto_pub -t "jerome.delacotte@gmail.com/chambre/volet" -m "s" + sleep 1 + mosquitto_pub -t "jerome.delacotte@gmail.com/theo/volet" -m "s" + sleep 1 + mosquitto_pub -t "jerome.delacotte@gmail.com/manon/volet" -m "s" +else + mosquitto_pub -t "jerome.delacotte@gmail.com/chambre/volet" -m "u" + sleep 1 + mosquitto_pub -t "jerome.delacotte@gmail.com/theo/volet" -m "u" + sleep 1 + mosquitto_pub -t "jerome.delacotte@gmail.com/manon/volet" -m "u" +fi + #statements + +echo "Apres" >>/tmp/test +lockfile-remove "/tmp/volet.lockfile" + diff --git a/volets2.sh b/volets2.sh new file mode 100755 index 0000000..e176f22 --- /dev/null +++ b/volets2.sh @@ -0,0 +1,53 @@ +#!/bin/bash + DOMO_IP="localhost" # Domoticz IP Address + DOMO_PORT="81" # Domoticz Port + Gauche_IDX=684 # cuisine + Droit_IDX=701 # téle + Milieu_IDX=699 # porte + duree=$2 + +lockfile-create "/tmp/volet2.lockfile" + +echo "Avant $1" >>/tmp/test +curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$Droit_IDX&switchcmd=$1" & +sleep $duree +curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$Droit_IDX&switchcmd=$1" & +sleep 2 +curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$Milieu_IDX&switchcmd=$1" & +sleep $duree +curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$Milieu_IDX&switchcmd=$1" & +sleep 2 +curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$Gauche_IDX&switchcmd=$1" & +sleep $duree +curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$Gauche_IDX&switchcmd=$1" & +sleep 2 + +if [ "$1" = "On" ] +then + mosquitto_pub -t "jerome.delacotte@gmail.com/chambre/volet" -m "d" + sleep 1 + mosquitto_pub -t "jerome.delacotte@gmail.com/theo/volet" -m "d" + sleep 1 + mosquitto_pub -t "jerome.delacotte@gmail.com/manon/volet" -m "d" + sleep 8 + mosquitto_pub -t "jerome.delacotte@gmail.com/chambre/volet" -m "s" + sleep 1 + mosquitto_pub -t "jerome.delacotte@gmail.com/theo/volet" -m "s" + sleep 1 + mosquitto_pub -t "jerome.delacotte@gmail.com/manon/volet" -m "s" +else + mosquitto_pub -t "jerome.delacotte@gmail.com/chambre/volet" -m "u" + sleep 1 + mosquitto_pub -t "jerome.delacotte@gmail.com/theo/volet" -m "u" + sleep 1 + mosquitto_pub -t "jerome.delacotte@gmail.com/manon/volet" -m "u" +fi + +# curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=822&switchcmd=$1&parsetrigger=false" & +# curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=823&switchcmd=$1&parsetrigger=false" & +# curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=824&switchcmd=$1&parsetrigger=false" & + + + +echo "Apres" >>/tmp/test +lockfile-remove "/tmp/volet2.lockfile" diff --git a/volets3.sh b/volets3.sh new file mode 100755 index 0000000..4bee96e --- /dev/null +++ b/volets3.sh @@ -0,0 +1,17 @@ +#!/bin/bash + DOMO_IP="localhost" # Domoticz IP Address + DOMO_PORT="81" # Domoticz Port + Gauche_IDX=684 # numéro ID de l interrupteur du relais + Droit_IDX=701 + Milieu_IDX=699 + + +lockfile-create "/tmp/volet3.lockfile" +echo "Avant $1" >>/tmp/test +curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$Droit_IDX&switchcmd=$1" & +sleep 1 +curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$Milieu_IDX&switchcmd=$1" & +sleep 1 +curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$Gauche_IDX&switchcmd=$1" & +echo "Apres" >>/tmp/test +lockfile-remove "/tmp/volet3.lockfile" diff --git a/volets4.sh b/volets4.sh new file mode 100755 index 0000000..9780f16 --- /dev/null +++ b/volets4.sh @@ -0,0 +1,25 @@ +#!/bin/bash + DOMO_IP="localhost" # Domoticz IP Address + DOMO_PORT="81" # Domoticz Port + Gauche_IDX=684 # numéro ID de l interrupteur du relais + Droit_IDX=701 + Milieu_IDX=699 + duree=$2 + +lockfile-create "/tmp/volet4.lockfile" + +echo "Avant $1" >>/tmp/test +curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$Droit_IDX&switchcmd=$1" & +sleep $duree +curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$Droit_IDX&switchcmd=$1" & +sleep 2 +curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$Milieu_IDX&switchcmd=$1" & +sleep $duree +curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$Milieu_IDX&switchcmd=$1" & +sleep 2 +curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$Gauche_IDX&switchcmd=$1" & +sleep $duree +curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command¶m=switchlight&idx=$Gauche_IDX&switchcmd=$1" & + +echo "Apres" >>/tmp/test +lockfile-remove "/tmp/volet4.lockfile" diff --git a/voletsSomfy.sh b/voletsSomfy.sh new file mode 100755 index 0000000..7f56750 --- /dev/null +++ b/voletsSomfy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +lockfile-create "/tmp/voletSomfy.lockfile" + +mosquitto_pub -t "jerome.delacotte@gmail.com/chambre/volet" -m "$1" +#mosquitto_pub -h www.maqiatto.com -u jerome.delacotte@gmail.com -P setaou -I clientId-9FG7vBimhk -t "jerome.delacotte@gmail.com/chambre/volet" -m $1 +sleep 1 +#mosquitto_pub -h www.maqiatto.com -u jerome.delacotte@gmail.com -P setaou -I clientId-9FG7vBimhk -t "jerome.delacotte@gmail.com/theo/volet" -m $1 +mosquitto_pub -t "jerome.delacotte@gmail.com/theo/volet" -m "$1" +sleep 1 +#mosquitto_pub -h www.maqiatto.com -u jerome.delacotte@gmail.com -P setaou -I clientId-9FG7vBimhk -t "jerome.delacotte@gmail.com/manon/volet" -m $1 +mosquitto_pub -t "jerome.delacotte@gmail.com/manon/volet" -m "$1" +lockfile-remove "/tmp/voletSomfy.lockfile" + diff --git a/voletsSomfyUnique.sh b/voletsSomfyUnique.sh new file mode 100755 index 0000000..7519e17 --- /dev/null +++ b/voletsSomfyUnique.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +lockfile-create "/tmp/voletSomfy.lockfile" + +#mosquitto_pub -h www.maqiatto.com -u jerome.delacotte@gmail.com -P setaou -I clientId-9FG7vBimhk -t "jerome.delacotte@gmail.com/$2/volet" -m $1 +mosquitto_pub -t "jerome.delacotte@gmail.com/$2/volet" -m $1 +lockfile-remove "/tmp/voletSomfy.lockfile" + diff --git a/wbs.php b/wbs.php new file mode 100644 index 0000000..600c57a --- /dev/null +++ b/wbs.php @@ -0,0 +1,420 @@ + + * File: wbs.php + * + * Withings Bodyscale Services API (WBS API) is a set of webservices allowing developers and third parties limited access to users' data. + * + * http://www.withings.com/en/api/bodyscale + * + * Copyright (c) 2010, Stefan Andersen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL STEFAN ANDERSEN BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +class remoteCallWbsException extends Exception {} +class validationErrorWbsException extends Exception {} + +abstract class wbs { + const WBSAPIHOST = 'wbsapi.withings.net'; + + private $responseCodes = array( + 'account-2555' => "An unknown error occurred", + 'account-264' => "The email address provided is either unknown or invalid", + 'account-100' => "The hash is missing, invalid, or does not match the provided email", + 'getmeas-2555' => "An unknown error occurred", + 'getmeas-250' => "The userid and publickey provided do not match, or the user does not share its data", + 'getmeas-247' => "The userid provided is absent, or incorrect", + ); + + /** + * Can we probe the remote api? + * + * @return boolean + */ + public function probe() { + return ($this->callWbs('once', 'probe') === false) ? false : true; + } + + /** + * Fetches magic string for computing password hash + * + * @return string + */ + protected function getMagicString() { + $result = $this->callWbs('once', 'get'); + return $result['body']['once']; + } + + /** + * Calls remote WBS API + * + * @param string $service + * @param string $action + * @param array $parameters + * @return false | result + */ + protected function callWbs($service, $action, $parameters = array()) + { + $url = sprintf('http://%s/%s?action=%s&%s', + self::WBSAPIHOST, + $service, + $action, + implode('&', $parameters)); + $ch = curl_init(); + curl_setopt($ch, CURLOPT_POST, false); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_URL, $url); + $result = json_decode(curl_exec($ch), true); + curl_close($ch); + + if (!is_array($result)) { + throw new remoteCallWbsException("Didn't get a valid array in response"); + } + if (!key_exists('status', $result)) { + throw new remoteCallWbsException("No status en response body"); + } + if ($result['status'] != 0) { + $statusKey = sprintf('%s-%s', $service, $result['status']); + if (key_exists($statusKey, $this->responseCodes)) { + throw new remoteCallWbsException($this->responseCodes[$statusKey]); + } + throw new remoteCallWbsException(sprintf("WBS returned error code: %s", $result['status'])); + } + return $result; + } +} + +class wbs_Account extends wbs { + protected $userEmail; + protected $userPassword; + + public function getUsersList() { + if (!is_string($this->userEmail)) { + throw new validationErrorWbsException("userEmail not set, call setUserEmail(email) first"); + } + if (!is_string($this->userPassword)) { + throw new validationErrorWbsException("userEmail not set, call setUserPassword(password) first"); + } + + $magic = $this->getMagicString(); + $hash = md5(sprintf('%s:%s:%s', + $this->userEmail, + md5($this->userPassword), + $magic)); + $params = array("email={$this->userEmail}", + "hash={$hash}"); + $result = $this->callWbs('account', 'getuserslist', $params); + foreach($result['body']['users'] as $user) { + $users[] = new wbs_User($user); + } + return (count($users) > 0)? $users : false; + } + + public function setUserEmail($email) { + $this->userEmail = $email; + } + + public function setUserPassword($password) { + $this->userPassword = $password; + } +} + +class wbs_User extends wbs { + protected $id; // The user identifier + protected $firstname; // The user's firstname, as an UTF-8 encoded string + protected $lastname; // The user's lastname, as an UTF-8 encoded string + protected $shortname; // The user's shortname + protected $gender; // The user's gender (0 for male, 1 for female) + protected $fatmethod; // Byte indicating the Body Composition Formula in use + protected $birthdate; // The user's birthdate in Epoch format + protected $ispublic; // Set to 1 if the user curently shares their data + protected $publickey; // The user's current publickey + + protected $startdate; // Will prevent retrieval of values dated prior to the supplied parameter. + protected $enddate; // Will prevent retrieval of values dated after the supplied parameter. + protected $meastype; // Will restrict the type of data retrieved + protected $lastupdate; // Only entries which have been added or modified since this time are retrieved. + protected $category; // Can be set to 2 to retrieve objectives or to 1 to retrieve actual measurements. + protected $limit; // Can be used to limit the number of measure groups returned in the result. + protected $offset; // Can be used to skip the 'offset' most recent measure group records of the result set. + + protected $measures; + + /** + * Constructs a wbs_User obj. Must supply information about user in array. + * + * @param array $fromArray + */ + public function __construct($fromArray) { + $this->id = $fromArray['id']; + $this->firstname = $fromArray['firstname']; + $this->lastname = $fromArray['lastname']; + $this->shortname = $fromArray['shortname']; + $this->gender = $fromArray['gender']; + $this->fatmethod = $fromArray['fatmethod']; + $this->birthdate = $fromArray['birthdate']; + $this->ispublic = $fromArray['ispublic']; + $this->publickey = $fromArray['publickey']; + } + + static function loadUser($userid, $publickey) { + $params = array("userid={$userid}", + "publickey={$publickey}"); + $result = parent::callWbs('user', 'getbyuserid', $params); + $result = $result['body']['users'][0]; + $result['publickey'] = $publickey; + return new wbs_User($result); + } + + public function getFullname() { + return $this->lastname . ", " . $this->firstname; + } + + public function getMeasures($allowCache = true) { + if ($allowCache && is_array($this->measures)) { + return $this->measures; + } + $params = array("userid={$this->id}", + "publickey={$this->publickey}"); + if (is_int($this->startdate)) { + $params[] = "startdate={$this->startdate}"; + } + if (is_int($this->enddate)) { + $params[] = "enddate={$this->enddate}"; + } + if (is_int($this->meastype)) { + $params[] = "meastype={$this->meastype}"; + } + if (is_int($this->lastupdate)) { + $params[] = "lastupdate={$this->lastupdate}"; + } + if (is_int($this->category)) { + $params[] = "category={$this->category}"; + } + if (is_int($this->limit)) { + $params[] = "limit={$this->limit}"; + } + if (is_int($this->offset)) { + $params[] = "offset={$this->offset}"; + } + $result = $this->callWbs('measure', 'getmeas', $params); + foreach ($result['body']['measuregrps'] as $measuregroup) { + $this->measures[] = new wbs_MeasureGroup($measuregroup); + } + return $this->measures; + } + + /** + * For a user's data to be accessible through this API, a prior authorization has to be given. + * + * @param boolean $public + * @return boolean + */ + public function setPublic($public) { + $params = array("userid={$this->id}", + "publickey={$this->publickey}"); + switch ($public) { + case true: + $params[] = "ispublic=1"; + break; + case false: + $params[] = "ispublic=0"; + break; + default: + throw new validationErrorWbsException("Public should be set to true or false"); + break; + } + $this->callWbs('user', 'update', $params); + return true; + } + + public function setStartdate($startdate) { + $this->startdate = $startdate; + } + + public function setEnddate($enddate) { + $this->enddate = $enddate; + } + + public function setMeastype($meastype) { + $this->meastype = $meastype; + } + + public function setLastupdate($lastupdate) { + $this->lastupdate = $lastupdate; + } + + public function setCategory($category) { + $this->category = $category; + } + + public function setLimit($limit) { + $this->limit = $limit; + } + + public function setOffset($offest) { + $this->offset = $offset; + } + + public function getId() { + return $this->id; + } +} + +class wbs_MeasureGroup { + protected $grpid; // A unique grpid (Group Id), useful for performing synchronization tasks. + protected $attrib; // An attrib (Attribute), defining the way the measure was attributed to the user. + protected $date; // The date (EPOCH format) at which the measure was taken or entered. + protected $category; // The category of the group. + protected $measures; + + public function __construct($fromArray) { + $this->grpid = $fromArray['grpid']; + $this->attrib = $fromArray['attrib']; + $this->date = $fromArray['date']; + $this->category = $fromArray['category']; + + foreach ($fromArray['measures'] as $measure) { + $this->measures[] = new wbs_Measure($measure); + } + } + + /** + * Attribution status + * + * Return values: + * 0 The measuregroup has been captured by a device and is known to belong to this user (and is not ambiguous) + * 1 The measuregroup has been captured by a device but may belong to other users as well as this one (it is ambiguous) + * 2 The measuregroup has been entered manually for this particular user + * 4 The measuregroup has been entered manually during user creation (and may not be accurate) + * + * @return int + */ + public function getAttrib() { + return $this->attrib; + } + + public function getAttribText() { + switch ($this->attrib) { + case 0: + return "Captured by device, belongs to this user"; + case 1: + return "Captured by device, belongs others users as well"; + case 2: + return "Entered manually, belongs to this user"; + case 4: + return "Entered manually during creating, not accurate"; + default: + return "unknown"; + } + } + + /** + * + * @return int + */ + public function getDate() { + return $this->date; + } + + /** + * Retun values: + * 1 Measure + * 2 Target + * + * @return int + */ + public function getCategory() { + return $this->category; + } + + /** + * Returns an array of wbs_Meassure's + * + * @return wbs_Measure[] + */ + public function getMeasures() { + return $this->measures; + } +} + +class wbs_Measure { + protected $type; + protected $value; + protected $unit; + + public function __construct($fromArray) { + $this->type = $fromArray['type']; + $this->value = $fromArray['value']; + $this->unit = $fromArray['unit']; + } + + /** + * Return values: + * 1 Weight (kg) + * 4 Height (meter) + * 5 Fat Free Mass (kg) + * 6 Fat Ratio (%) + * 8 Fat Mass Weight (kg) + * + * @return int + */ + public function getType() { + return $this->type; + } + + public function getValue() { + return $this->value * pow(10, $this->unit); + } + + public function getUnitPrefix() { + switch ($this->type) { + case 1: + return "Weight"; + case 4: + return "Height"; + case 5: + return "Fat Free Mass"; + case 6: + return "Fat Ratio"; + case 8: + return "Fat Mass Weight"; + default: + return "unknown"; + } + } + + public function getUnitSuffix() { + if (in_array($this->type, array(1, 5, 8))) { + return "kg"; + } elseif ($this->type == 4) { + return "meter"; + } elseif ($this->type == 6) { + return "%"; + } + return "unknown"; + } +} + diff --git a/withingjd.php b/withingjd.php new file mode 100644 index 0000000..3ebfdfb --- /dev/null +++ b/withingjd.php @@ -0,0 +1,30 @@ +setUserEmail('souti@free.fr'); + $wbs->setUserPassword('setaou'); + + $usersList = $wbs->getUsersList(); + foreach ($usersList as $user) { + if ($user->getFullname() == "Delacotte, Jérôme") { + $user->setLimit(3); + $measuresgroups = $user->getMeasures(); + $name=substr($user->getFullname(),0,strlen($user->getFullname())); + foreach($measuresgroups as $group) { + $ligne=""; + $ligne=$ligne.date('Y-m-d', $group->getDate()) . ","; + $ligne=$ligne.date('H:i:s', $group->getDate()) . ","; + foreach($group->getMeasures() as $measure) { + $balise=str_replace(" ","-",$measure->getUnitPrefix()); + $ligne.=$measure->getValue(); + $ligne.=",".$measure->getUnitSuffix().","; + } + if (strpos($ligne,"unknown") == false) { + print $ligne."\n"; + } + } + } + } + + diff --git a/withings.sh b/withings.sh new file mode 100755 index 0000000..6bb5a2b --- /dev/null +++ b/withings.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +cd /opt/domoticz/scripts/ +withings=`php withingjd.php` +#poids=$withings |awk -F "," '{print $3}' +#seche=php jd.php |awk -F "," '{print $5}' +#mg=php jd.php |awk -F "," '{print $7}' + +arr=$(echo $withings | tr "," "\n") +i=0 +j=7 +mg=0.0 +pds=0.0 +for x in $arr +do + #echo "> [$x]" + i=$((i+1)) + if [ "$j" -eq "$i" ] + then + mg=$x + echo "mg> [$x]" + fi + if [ 3 -eq "$i" ] + then + pds=$x + echo "pds > [$x]" + fi +done +#echo $mg + +if [ "$withings" != "" ] +then + json="http://localhost:81/json.htm?type=command¶m=udevice&idx=327&nvalue=$mg&svalue=$mg" + json2="http://localhost:81/json.htm?type=command¶m=udevice&idx=326&nvalue=$mg&svalue=$pds" + #echo $json + curl -s -i -H "Accept: application/json" $json >/dev/null + curl -s -i -H "Accept: application/json" $json2 >/dev/null +else + echo "echec de recuperation" +fi +