├── CONTRIBUTING.md
├── install
├── diag.sh
├── alpha
│ ├── autoupdate.data
│ ├── Python3
│ │ ├── autoupdate.data
│ │ └── thermeq3.zip
│ ├── thermeq3.zip
│ ├── watch_bridge
│ └── readme.md
├── current
│ ├── autoupdate.data
│ ├── thermeq3.zip
│ └── config_me.py
├── RPi
│ ├── thermeq3.zip
│ ├── readme.md
│ ├── diag.sh
│ ├── install-dash.sh
│ └── install.sh
├── dashboard
│ ├── yun-dash.sh
│ ├── README.md
│ └── rpi-dash.sh
└── uni_install.sh
├── obsolete
├── install
│ ├── autoupdate.data
│ ├── V231
│ │ ├── autoupdate.data
│ │ ├── thermeq3.zip
│ │ ├── config.py
│ │ └── install.sh
│ ├── alpha_Yun_Rev2
│ │ ├── readme.md
│ │ └── install.sh
│ ├── config.py
│ ├── install.sh
│ └── README.md
├── lib
│ ├── nsm.py
│ ├── action.py
│ ├── public_ip.py
│ ├── dummy.py
│ ├── config.py
│ ├── secweb.py
│ ├── support.py
│ ├── logmsg.py
│ ├── csvfile.py
│ ├── profiles.py
│ ├── weather.py
│ ├── autoupdate.py
│ ├── mailer.py
│ ├── bridge.py
│ ├── t3_var.py
│ └── maxeq3.py
├── create_nsm.sh
├── support
│ └── sample temperature.py
├── tasker
│ ├── parseyun.js
│ └── parseyun-tasker.xml
├── recreate_http.sh
└── betabeat
│ └── html
│ └── setup.html
├── sketch
├── Capture.PNG
└── thermeq3.fzz
├── flowchart
└── flowchart_1.png
├── support
├── readme.md
├── del_dev.py
└── testrelay.py
├── .gitattributes
├── .github
└── ISSUE_TEMPLATE
│ ├── feature_request.md
│ └── bug_report.md
├── eInk Display
├── README.md
└── sketch
│ └── exthermeq.ino
├── CODE_OF_CONDUCT.md
├── .gitignore
├── yun-sketch
├── thermeq3_V200
│ └── thermeq3_V200.ino
├── thermeq3
│ └── thermeq3.ino
└── thermeq3_dht
│ └── thermeq3_dht.ino
└── README.md
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Feel free to test and comment.
2 |
--------------------------------------------------------------------------------
/install/diag.sh:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/autopower/thermeq3/HEAD/install/diag.sh
--------------------------------------------------------------------------------
/obsolete/install/autoupdate.data:
--------------------------------------------------------------------------------
1 | 155:nsm.py:60096:4ca7c6d25b4972de5166dabf959d9e8f
2 |
--------------------------------------------------------------------------------
/install/alpha/autoupdate.data:
--------------------------------------------------------------------------------
1 | 309:thermeq3.zip:40541:0661c29dd8372d08ac7fc964fa88153e
2 |
--------------------------------------------------------------------------------
/install/current/autoupdate.data:
--------------------------------------------------------------------------------
1 | 286:thermeq3.zip:35173:59233d1115b982d9c256aa91e411e97e
2 |
--------------------------------------------------------------------------------
/sketch/Capture.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/autopower/thermeq3/HEAD/sketch/Capture.PNG
--------------------------------------------------------------------------------
/sketch/thermeq3.fzz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/autopower/thermeq3/HEAD/sketch/thermeq3.fzz
--------------------------------------------------------------------------------
/install/alpha/Python3/autoupdate.data:
--------------------------------------------------------------------------------
1 | 300:thermeq3.zip:35474:00bd10c69a954b13ee79fe8925d7f35c
2 |
--------------------------------------------------------------------------------
/obsolete/install/V231/autoupdate.data:
--------------------------------------------------------------------------------
1 | 231:thermeq3.zip:28394:c324f372cafaa93fc3d489a2cc052244
2 |
--------------------------------------------------------------------------------
/install/RPi/thermeq3.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/autopower/thermeq3/HEAD/install/RPi/thermeq3.zip
--------------------------------------------------------------------------------
/flowchart/flowchart_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/autopower/thermeq3/HEAD/flowchart/flowchart_1.png
--------------------------------------------------------------------------------
/install/alpha/thermeq3.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/autopower/thermeq3/HEAD/install/alpha/thermeq3.zip
--------------------------------------------------------------------------------
/install/current/thermeq3.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/autopower/thermeq3/HEAD/install/current/thermeq3.zip
--------------------------------------------------------------------------------
/install/alpha/Python3/thermeq3.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/autopower/thermeq3/HEAD/install/alpha/Python3/thermeq3.zip
--------------------------------------------------------------------------------
/obsolete/install/V231/thermeq3.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/autopower/thermeq3/HEAD/obsolete/install/V231/thermeq3.zip
--------------------------------------------------------------------------------
/obsolete/install/alpha_Yun_Rev2/readme.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/autopower/thermeq3/HEAD/obsolete/install/alpha_Yun_Rev2/readme.md
--------------------------------------------------------------------------------
/obsolete/lib/nsm.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import thermeq3
3 |
4 |
5 | if __name__ == '__main__':
6 | thermeq3.start()
7 | thermeq3.loop()
8 |
--------------------------------------------------------------------------------
/install/alpha/watch_bridge:
--------------------------------------------------------------------------------
1 | #!/bin/ash
2 | if [ $(( (`date +%s` - `date -r /mnt/sda1/peklotest.bridge +%s`) > (5 * 60) )) -eq 1 ]; then
3 | ps -ef | grep nsm.py | grep -v grep | awk '{print }' | xargs kill -9
4 | fi
5 |
--------------------------------------------------------------------------------
/obsolete/create_nsm.sh:
--------------------------------------------------------------------------------
1 | #!/bin/ash
2 | echo "Creating nsm.py compatibility file"
3 | echo "#!/usr/bin/env python
4 | import sys
5 |
6 | sys.path.insert(0, \"/root/thermeq3/\")
7 | execfile(\"/root/thermeq3/nsm.py\")
8 | " > /root/nsm.py
--------------------------------------------------------------------------------
/obsolete/install/config.py:
--------------------------------------------------------------------------------
1 | stp.max_ip = "192.168.0.10"
2 | stp.fromaddr = "devices@foo.local"
3 | stp.toaddr = "user@foo.local"
4 | stp.mailserver = "mail.foo.local"
5 | stp.mailport = 25
6 | stp.frompwd = "this.is.password"
7 | stp.devname = "hellmostat"
8 | stp.timeout = 10
9 | stp.api_key = "blablabla"
--------------------------------------------------------------------------------
/obsolete/support/sample temperature.py:
--------------------------------------------------------------------------------
1 | import math
2 |
3 | def scale(val, src, dst):
4 | return ((val - src[0]) / (src[1]-src[0])) * (dst[1]-dst[0]) + dst[0]
5 |
6 | _min = 1.7
7 | _max = 3.0
8 | for each in range(-35, 36):
9 | a = scale(each, (0.0, 35.0), (_min, _max))
10 | print "%3i" % each, "=", "% 2.4f" % a, "% 3i" % int(scale(math.exp(a), (math.exp(_min), math.exp(_max)), (15, 120)))
11 |
12 |
--------------------------------------------------------------------------------
/obsolete/lib/action.py:
--------------------------------------------------------------------------------
1 | import RPi.GPIO as GPIO
2 |
3 |
4 | def start():
5 | GPIO.setwarnings(False)
6 | GPIO.setmode(GPIO.BCM)
7 | GPIO.setup(18, GPIO.OUT)
8 | # GPIO pin 18 is for DEV, prod is 17
9 |
10 |
11 | def do(action):
12 | if action:
13 | gpio_action = GPIO.HIGH
14 | else:
15 | gpio_action = GPIO.LOW
16 | try:
17 | GPIO.output(18, gpio_action)
18 | # PIN 18 if for DEV, 17 for PROD
19 | finally:
20 | pass
21 |
--------------------------------------------------------------------------------
/support/readme.md:
--------------------------------------------------------------------------------
1 | ## Support code for thermeq3
2 |
3 | # test-relay.py
4 | This simple code test relay for RPi, check relay if it is NO or NC.
5 | Please run `python testrelay.py` and follow instructions.
6 |
7 | How to download: `wget --no-check-certificate --quiet --output-document /home/pi/testrelay.py https://raw.githubusercontent.com/autopower/thermeq3/master/install/RPi/test_relay/testrelay.py;chmod +x /home/pi/testrelay.py`
8 |
9 | # del-dev.py
10 | Simple code for deleting device from Max!Cube, please use it with caution.
11 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.sln merge=union
7 | *.csproj merge=union
8 | *.vbproj merge=union
9 | *.fsproj merge=union
10 | *.dbproj merge=union
11 |
12 | # Standard to msysgit
13 | *.doc diff=astextplain
14 | *.DOC diff=astextplain
15 | *.docx diff=astextplain
16 | *.DOCX diff=astextplain
17 | *.dot diff=astextplain
18 | *.DOT diff=astextplain
19 | *.pdf diff=astextplain
20 | *.PDF diff=astextplain
21 | *.rtf diff=astextplain
22 | *.RTF diff=astextplain
23 |
--------------------------------------------------------------------------------
/install/alpha/readme.md:
--------------------------------------------------------------------------------
1 | # Alpha version
2 | Not so very well tested version.
3 | Just for test issues.
4 |
5 | ## Whats new?
6 | * new dahsboard, please edit dash file in cgi-bin, add `$QUERY_STRING` to the end of python line
7 | * RPi support
8 | * new config file format (json)
9 | * auto convert old config file and rename old one
10 | * send mail issues resolved
11 | * code clean up
12 | * win nt & rpi support
13 | * lifetime valve ignore
14 | * weather fixes
15 |
16 | ## How to upgrade
17 | Please [follow link](https://github.com/autopower/thermeq3/wiki/install-application#i-want-to-install-latest-working-alpha-version).
18 |
--------------------------------------------------------------------------------
/obsolete/tasker/parseyun.js:
--------------------------------------------------------------------------------
1 | // JavaScript Document
2 | var arr = [];
3 | var tmp = [];
4 | var owl_title = "";
5 | var owl_text = "";
6 | var j = [];
7 |
8 | arr = JSON.parse(global("HTTPD"));
9 |
10 | if (arr.value.length > 2) {
11 | tmp = arr.value.slice(1, -1).split(",");
12 | } else {
13 | tmp = "";
14 | }
15 |
16 | if (tmp.length == 0) {
17 | owl_title = "Everything OK"
18 | owl_text = "All windows closed."
19 | } else {
20 | owl_title = "Act now!"
21 | owl_text = tmp.length + " window(s) opened in room(s): "
22 | for (i=0; i < tmp.length; i++) {
23 | j = tmp[i].split(":");
24 | owl_text += " " + j[1].slice(2, -1);
25 | }
26 | }
--------------------------------------------------------------------------------
/obsolete/install/V231/config.py:
--------------------------------------------------------------------------------
1 | # Please strictly use quotation marks!
2 | # Reported name of this thermeq3 installation, ie. "thermeq3"
3 | self.devname = None
4 | # MAX Cube,ie. "192.168.0.10"
5 | self.max_ip = None
6 | # e-mail
7 | # ie. "devices@foo.local"
8 | self.fromaddr = None
9 | # ie. "user@foo.local"
10 | self.toaddr = None
11 | # SMTP host ie. "mail.foo.local"
12 | self.mailserver = None
13 | # SMTP port ie. 25
14 | self.mailport = None
15 | # SMTP authentication password, ie. "password"
16 | self.frompwd = None
17 | # Weather info
18 | # open weather map API key, ie "123456789"
19 | self.owm_api_key = None
20 | # geographic location, as per Yahoo WOEID. ie. "12345"
21 | self.location = None
22 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/obsolete/recreate_http.sh:
--------------------------------------------------------------------------------
1 | #!/bin/ash
2 | if [ -d /mnt/sda1 ]; then
3 | DIR=/mnt/sda1
4 | else
5 | if [ -d /mnt/sdb1 ]; then
6 | DIR=/mnt/sdb1
7 | else
8 | echo "Please mount USB or SD card!"
9 | exit 1
10 | fi
11 | fi
12 | echo "Using $DIR as storage path."
13 | echo "Recreating directories and cgi scripts"
14 | mkdir -p $DIR/www
15 | cd $DIR/www
16 | mkdir -p $DIR/csv
17 | cd $DIR/www
18 | mkdir -p cgi-bin
19 | cd cgi-bin
20 |
21 | echo "#!/bin/sh
22 | echo \"Content-type: application/json\"
23 | echo \"\"
24 | cat $DIR/www/status.xml" > status
25 | echo "#!/bin/sh
26 | echo \"Content-type: application/json\"
27 | echo \"\"
28 | cat $DIR/www/owl.xml" > owl
29 | echo "#!/bin/sh
30 | echo \"Content-type: text/html\"
31 | echo \"\"
32 | cat $DIR/www/nice.html" > nice
33 | chmod +x status
34 | chmod +x owl
35 | chmod +x nice
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Logs**
24 | If applicable, add logs to help explain your problem.
25 |
26 | **themreq3 (please complete the following information):**
27 | - OS: [e.g. OpenWRT]
28 | - Python [e.g. 2/3]
29 | - version [e.g. V298]
30 |
31 | **Hardware:**
32 | - Device: [yun/yun2/rpi/docker/linux/windows]
33 | - OS: [e.g. OpenWRT...]
34 | - Python [e.g. 2/3]
35 |
36 | **Additional context**
37 | Add any other context about the problem here.
38 |
--------------------------------------------------------------------------------
/install/RPi/readme.md:
--------------------------------------------------------------------------------
1 | # Installation on RPi
2 |
3 | ## Hardware installation
4 | Please take a look at [wiki page](https://github.com/autopower/thermeq3/wiki/Setup-RPi-hardware).
5 | ## thermeq3 installation
6 | This is very early alpha, please be very patient.
7 | Please take a look at [wiki page](https://github.com/autopower/thermeq3/wiki/install-application).
8 |
9 | ## Get config file support
10 | `wget --no-check-certificate --quiet --output-document /home/pi/thermeq3/config_me.py https://raw.githubusercontent.com/autopower/thermeq3/master/install/current/config_me.py;chmod +x /home/pi/thermeq3/config_me.py`
11 | and run it:
12 | ```
13 | cd /home/pi/thermeq3
14 | ./config_me.py
15 | ```
16 | Please answer questions and check final config file in JSON format vi `cat` or `vi`.
17 |
18 | ## Diagnostics
19 | Download diag.sh `wget --no-check-certificate --quiet --output-document /home/pi/thermeq3/diag.sh https://raw.githubusercontent.com/autopower/thermeq3/master/install/RPi/diag.sh; chmod +x /home/pi/thermeq3/diag.sh`
20 |
--------------------------------------------------------------------------------
/eInk Display/README.md:
--------------------------------------------------------------------------------
1 | # eInk display for thermeq3
2 | Simple device with eInk display based of ESP8266 and 2.7 eInk display.
3 | This sketch using Waveshare [ESP8266 driver](https://www.waveshare.com/wiki/E-Paper_ESP8266_Driver_Board) and [2.7" display module](https://www.waveshare.com/wiki/2.7inch_e-Paper_HAT_(B)).
4 | Please download [library](https://www.waveshare.com/wiki/File:2.7inch_e-paper_hat_b_code.7z) for 2.7" display, edit pin definitions in `epdif.h`:
5 | ```
6 | #define CS_PIN 15
7 | #define RST_PIN 5
8 | #define DC_PIN 4
9 | #define BUSY_PIN 16
10 | ```
11 | Finally you must edit sketch values for WiFi:
12 | ```
13 | #define SSID_NAME "Your_SSID"
14 | #define SSID_PWD "Your_key"
15 | ```
16 | Code using deep sleep feature on ESP, so you must connect GPIO16 and RST pin of ESP via 10k resitor, to correctly wake up.
17 | And upload sketch to ESP via Arduino IDE.
18 |
19 | thmermeq3 version must be 250+ and second website with bridge support must be installed, please check `http://ardu.ip:8180/bridge.json` if working.
20 |
21 |
22 | # Thats all folks. Stay tuned :)
23 |
--------------------------------------------------------------------------------
/support/del_dev.py:
--------------------------------------------------------------------------------
1 | import socket
2 | import base64
3 |
4 |
5 | def read_lines():
6 | global client_socket
7 | lines_buffer = ""
8 | data = True
9 | while data:
10 | try:
11 | data = client_socket.recv(4096)
12 | lines_buffer += data
13 | except socket.timeout:
14 | break
15 | return lines_buffer
16 |
17 |
18 | print("thermeq3 delete device from MAX!Cube\n")
19 | # please edit max cube address
20 | max_ip = "192.168.0.200"
21 | # please edit device for deletion
22 | dev_id = "DEAD01"
23 | print("Deleting device id: " + dev_id + "from MAX!Cube with IP: " + max_ip)
24 |
25 | client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
26 | client_socket.settimeout(2)
27 | client_socket.connect((max_ip, 62910))
28 |
29 | result = read_lines()
30 |
31 | dev_id_plain = bytearray.fromhex(dev_id).decode()
32 | message = "t:01,1," + base64.b64encode(dev_id_plain) + "\r\n"
33 | client_socket.sendall(message)
34 |
35 | # result must be "A:"
36 | print("Command issued. Please read result. Result must begin with A:\n----------")
37 | print read_lines()
38 | client_socket.close()
39 |
--------------------------------------------------------------------------------
/install/dashboard/yun-dash.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | echo "thermeq3 dashboard install for yún"
3 | echo ""
4 | if [ -d /mnt/sda1 ]; then
5 | INSTALL_DIR=/mnt/sda1
6 | else
7 | if [ -d /mnt/sdb1 ]; then
8 | INSTALL_DIR=/mnt/sdb1
9 | else
10 | echo "Please mount USB or SD card!"
11 | exit 1
12 | fi
13 | fi
14 | echo "Using $INSTALL_DIR/www/cgi-bin as cgi-bin path."
15 | echo ""
16 | echo "Downloading dashboard..."
17 | wget --no-check-certificate --quiet -O $INSTALL_DIR/www/cgi-bin/dashboard.py https://github.com/autopower/thermeq3/raw/master/install/dashboard/dashboard.py
18 | if [ $? -ne 0 ]; then
19 | echo "Error during downloading dahsboard: $?"
20 | exit $?
21 | fi
22 |
23 | echo "Creating dash file"
24 | echo "#!/bin/sh
25 | /usr/bin/env python $INSTALL_DIR/www/cgi-bin/dashboard.py $QUERY_STRING" > $INSTALL_DIR/www/cgi-bin/dash
26 | chmod +x dash
27 |
28 | if ! grep -q "0.0.0.0:8180" /etc/config/uhttpd; then
29 | echo "Wrong uhttpd configuration. Please check /etc/config/uhttpd!"
30 | exit 1
31 | fi
32 |
33 | echo "Dashboard succesfully installed. Before browsing to http://arduino.ip:8180/cgi-bin/dash please edit base_dir and base_ip variables in dashboard.py file"
34 |
--------------------------------------------------------------------------------
/support/testrelay.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import RPi.GPIO as GPIO
3 | import time
4 |
5 | # if relay type is normally closed, set to True, normally open set to False
6 | relay_type = False
7 |
8 |
9 | def start():
10 | GPIO.setwarnings(False)
11 | GPIO.setmode(GPIO.BCM)
12 | GPIO.setup(4, GPIO.OUT)
13 |
14 |
15 | def do(action):
16 | global relay_type
17 | if relay_type:
18 | action = not action
19 | if action:
20 | gpio_action = GPIO.HIGH
21 | else:
22 | gpio_action = GPIO.LOW
23 | try:
24 | GPIO.output(4, gpio_action)
25 | finally:
26 | pass
27 |
28 |
29 | def do_test():
30 | global relay_type
31 | print "Using relay_type:", relay_type
32 | print "Now turning relay ON for 5sec"
33 | do(True)
34 | time.sleep(5)
35 | print "And now turn OFF"
36 | do(False)
37 |
38 |
39 | if __name__ == '__main__':
40 | print "Test relay for RPi"
41 | print "Please connect your relay control pin to PIN7 = GPIO4"
42 | start()
43 | print "Pin setup done."
44 | do_test()
45 | value = ""
46 | while not value == "y":
47 | value = raw_input("Please enter y if is this correct: ")
48 | if value == "y":
49 | pass
50 | else:
51 | relay_type = not relay_type
52 | do_test()
53 | print "You successfully setup relay. Please edit action.py, line relay_type = ", relay_type
54 |
--------------------------------------------------------------------------------
/install/dashboard/README.md:
--------------------------------------------------------------------------------
1 | # Dashboard for thermeq3
2 | Simple dashboard for boiler actor device.
3 | For complete thermeq3 readme, click [here](https://github.com/autopower/thermeq3/blob/master/README.md).
4 |
5 | To install thermeq3 *alpha* dashboard please type commands below, be sure that you are running V252+ and while logged in as root
6 |
7 | ## Installation instructions Yún
8 | * to get dashboard install script `wget --no-check-certificate --quiet -O /root/yun-dash.sh https://raw.githubusercontent.com/autopower/thermeq3/master/install/dashboard/yun-dash.sh;chmod +x /root/yun-dash.sh`
9 | * to run script `/root/yun-dash.sh`
10 |
11 | ## Installation instructions RPi
12 | * to get dashboard install script `wget --no-check-certificate --quiet -O /home/pi/rpi-dash.sh https://raw.githubusercontent.com/autopower/thermeq3/master/install/dashboard/rpi-dash.sh;chmod +x /root/rpi-dash.sh`
13 | * to run script `/home/pi/rpi-dash.sh`
14 |
15 | If script is not working, please update dashboard.py line `request = urllib2.Request("http://localhost:8180/" + str(url))` according to your setup, e.g.:
16 | * RPi users to `request = urllib2.Request("http://localhost/" + str(url))`
17 | * Yún users replace default port 8180 to port according to your uhttpd configuration `request = urllib2.Request("http://localhost:YOUR_PORT/" + str(url))`
18 |
19 | ### How to replace text in dashboard.py
20 | `sed -i -e 's/localhost:8180/localhost/g' /PATH_TO_FILE/dashboard.py`
21 |
--------------------------------------------------------------------------------
/obsolete/lib/public_ip.py:
--------------------------------------------------------------------------------
1 | import struct
2 | import socket
3 | import urllib2
4 | import os
5 |
6 |
7 | def is_private(lookup_ip):
8 | """
9 | Returns True if IP address is private, False if not
10 | :param lookup_ip: ip address
11 | :return: True
12 | """
13 | if os.name == "nt":
14 | f = struct.unpack('!I', socket.inet_aton(lookup_ip))[0]
15 | else:
16 | f = struct.unpack('!I', socket.inet_pton(socket.AF_INET, lookup_ip))[0]
17 | private = (
18 | [2130706432, 4278190080], # 127.0.0.0, 255.0.0.0 http://tools.ietf.org/html/rfc3330
19 | [3232235520, 4294901760], # 192.168.0.0, 255.255.0.0 http://tools.ietf.org/html/rfc1918
20 | [2886729728, 4293918720], # 172.16.0.0, 255.240.0.0 http://tools.ietf.org/html/rfc1918
21 | [167772160, 4278190080], # 10.0.0.0, 255.0.0.0 http://tools.ietf.org/html/rfc1918
22 | )
23 | for net in private:
24 | if f & net[1] == net[0]:
25 | return True
26 | return False
27 |
28 |
29 | def get():
30 | """
31 | Gets public IP, using service at ip.42.pl/raw address
32 | :return: ip address, if unsuccessful 0xFF
33 | """
34 | try:
35 | tmp_ip = str(urllib2.urlopen('http://ip.42.pl/raw').read())
36 | except Exception:
37 | try:
38 | tmp_ip = socket.gethostbyname(socket.gethostname())
39 | except Exception:
40 | tmp_ip = 0xFF
41 | return tmp_ip
42 |
--------------------------------------------------------------------------------
/install/RPi/diag.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | if [ $# -lt 1 ]; then
3 | echo "Usage: diag.sh "
4 | echo "diag.sh 192.168.0.222"
5 | exit 1
6 | fi
7 |
8 | DIAGFILE=/home/pi/thermeq3/diag.txt
9 |
10 | PKG_OK=$(dpkg-query -W --showformat='${Status}\n' telnet|grep "install ok installed")
11 | echo Checking for telnet: $PKG_OK
12 | if [ "" == "$PKG_OK" ]; then
13 | echo "No telnet. Installing telnet"
14 | sudo apt-get --yes install telnet
15 | fi
16 |
17 | if [ -f /home/pi/thermeq3/diag.txt ]; then
18 | echo "Previous diag.txt exists! Appending to file."
19 | fi
20 | echo "--- Diag script ---------" >> $DIAGFILE
21 | date >> $DIAGFILE
22 | echo "df..."
23 | echo "--- Diskfree ---------" >> $DIAGFILE
24 | df -h >> $DIAGFILE
25 | echo "mount..."
26 | echo "--- Mount point ---------" >> $DIAGFILE
27 | mount >> $DIAGFILE
28 | echo "ifconfig..."
29 | echo "--- i/f config ---------" >> $DIAGFILE
30 | ifconfig >> $DIAGFILE
31 | echo "ping..."
32 | echo "--- Ping ---------" >> $DIAGFILE
33 | ping $1 -c 4 >> $DIAGFILE
34 | echo "telnet..."
35 | echo "--- Telnet to MAX!Cube ---------" >> $DIAGFILE
36 | sleep 3 | telnet $1 62910 >> $DIAGFILE
37 | read -p "Include thermeq3.json file? WARNING: file may contains user credentials to email service! [y/n]" yn
38 | case $yn in
39 | [Yy]* )
40 | echo "--- thermeq3.json ---------" >> $DIAGFILE
41 | cat /home/pi/thermeq3/thermeq3.json >> $DIAGFILE
42 | ;;
43 | esac
44 | echo "Please post diag.txt to autopowerdevice@gmail.com"
--------------------------------------------------------------------------------
/obsolete/tasker/parseyun-tasker.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 1338504847144
4 | 1419613034489
5 | 14
6 | Get thermeq3 Status
7 | 10
8 |
9 | 118
10 | http://user:password@thermeq.ip/data/get/openwinlist
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | 37
22 |
23 |
24 | %HTTPR
25 | 0
26 | 200
27 |
28 |
29 |
30 |
31 | 131
32 | Tasker/js/parseyun.js
33 |
34 |
35 |
36 |
37 |
38 | 37
39 |
40 |
41 | %owl_title
42 | 3
43 | Everything OK
44 |
45 |
46 |
47 |
48 | 550
49 | %owl_title
50 | %owl_text
51 |
52 | Popup
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/obsolete/lib/dummy.py:
--------------------------------------------------------------------------------
1 | import thermeq3
2 | import datetime
3 |
4 |
5 | def add_dummy(status):
6 | """
7 | :param status: is window open?
8 | :return: nothing
9 | """
10 | # valves = {valve_adr: [valve_pos, valve_temp, valve_curtemp, valve_name]}
11 | # rooms = {id : [room_name, room_address, is_win_open, curr_temp, average valve position]}
12 | # devices = {addr: [type, serial, name, room, OW, OW_time, status, info, temp offset]}
13 | thermeq3.t3.eq3.rooms.update({"99": ["Dummy room", "DeadBeefValve", False, 22.0, 22]})
14 | thermeq3.t3.eq3.devices.update({"DeadBeefWindow": [4, "IHADBW", "Dummy window", 99, 0,
15 | datetime.datetime(2016, 01, 01, 12, 00, 00), 18, 16, 7]})
16 | thermeq3.t3.eq3.devices.update({"DeadBeefValve": [1, "IHADBV", "Dummy valve", 99, 0,
17 | datetime.datetime(2016, 01, 01, 12, 00, 00), 18, 56, 7]})
18 | thermeq3.t3.eq3.valves.update({"DeadBeefValve": [20, 22.0, 22.0, "Dummy valve"]})
19 | # TBI open/closed window
20 | if status:
21 | thermeq3.t3.eq3.devices["DeadBeefWindow"][4] = 2
22 | thermeq3.t3.eq3.devices["DeadBeefWindow"][5] = \
23 | datetime.datetime.now() - \
24 | datetime.timedelta(seconds=((thermeq3.t3.eq3.ignore_time + 10) * 60))
25 | thermeq3.t3.eq3.rooms["99"][2] = True
26 | else:
27 | thermeq3.t3.eq3.devices["DeadBeefWindow"][4] = 0
28 | thermeq3.t3.eq3.rooms["99"][2] = False
29 |
30 |
31 | def remove_dummy():
32 | del thermeq3.t3.eq3.rooms["99"]
33 | del thermeq3.t3.eq3.valves["DeadBeefValve"]
34 | del thermeq3.t3.eq3.devices["DeadBeefWindow"]
35 | del thermeq3.t3.eq3.devices["DeadBeefValve"]
36 |
--------------------------------------------------------------------------------
/install/RPi/install-dash.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | WWWDIR=/var/www/html
3 | CGIDIR=/usr/lib/cgi-bin
4 | BASE_DIR=/home/pi/thermeq3
5 |
6 | echo "Using $WWWDIR as base for html files"
7 | echo "Using $CGIDIR as cgi-bin path"
8 |
9 | PKG_OK=$(dpkg-query -W --showformat='${Status}\n' apache2|grep "install ok installed")
10 | echo "Checking for apache2: $PKG_OK"
11 | if [ "" == "$PKG_OK" ]; then
12 | echo "No apache2. Installing apache2"
13 | sudo apt-get --force-yes --yes install apache2
14 | if [ $? -ne 0 ]; then
15 | echo "Error during installing apache2 package. Error: $?"
16 | exit $?
17 | fi
18 | fi
19 |
20 | echo "Creating apache configuration..."
21 | sudo chown -R pi:www-data /var/www/html/
22 | sudo chmod -R 770 /var/www/html/
23 |
24 | echo "Downloading bootstrap"
25 | wget --no-check-certificate --quiet --output-document $WWWDIR/bootstrap.zip https://github.com/twbs/bootstrap/releases/download/v3.3.7/bootstrap-3.3.7-dist.zip
26 | echo "Unzipping bootstrap"
27 | unzip $WWWDIR/bootstrap.zip -d $WWWDIR/
28 | if [ $? -ne 0 ]; then
29 | echo "Error during unzipping thermeq3 app: $?"
30 | exit $?
31 | fi
32 | echo "Moving bootstrap..."
33 | cp -R $WWWDIR/bootstrap-3.3.7-dist/* $WWWDIR/
34 | rm -rf $WWWDIR/bootstrap-3.3.7-dist/
35 | rm -rf $WWWDIR/bootstrap.zip
36 |
37 | echo "Downloading dashboard..."
38 | sudo wget --no-check-certificate --quiet --output-document $CGIDIR/dashboard.py https://github.com/autopower/thermeq3/raw/master/install/dashboard/dashboard.py
39 | if [ $? -ne 0 ]; then
40 | echo "Error during downloading dashboard: $?"
41 | exit $?
42 | fi
43 |
44 | echo "Creating dash file"
45 | echo "#!/bin/sh
46 | /usr/bin/env python $CGIDIR/dashboard.py" > ~/dash
47 | sudo chmod +x ~/dash
48 | sudo mv ~/dash $CGIDIR/dash
49 |
50 | echo "Dashboard succesfully installed. Before browsing to http://rpi.ip/cgi-bin/dash please edit credentials in dashboard.py file"
51 |
--------------------------------------------------------------------------------
/install/dashboard/rpi-dash.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | echo "thermeq3 dashboard install for Rpi"
3 | echo ""
4 | WWWDIR=/var/www/html
5 | CGIDIR=/usr/lib/cgi-bin
6 | BASE_DIR=/home/pi/thermeq3
7 |
8 | echo "Using $WWWDIR as base for html files"
9 | echo "Using $CGIDIR as cgi-bin path"
10 |
11 | PKG_OK=$(dpkg-query -W --showformat='${Status}\n' apache2|grep "install ok installed")
12 | echo "Checking for apache2: $PKG_OK"
13 | if [ "" == "$PKG_OK" ]; then
14 | echo "No apache2. Installing apache2"
15 | sudo apt-get --force-yes --yes install apache2
16 | if [ $? -ne 0 ]; then
17 | echo "Error during installing apache2 package. Error: $?"
18 | exit $?
19 | fi
20 | fi
21 |
22 | echo "Creating apache configuration..."
23 | sudo chown -R pi:www-data /var/www/html/
24 | sudo chmod -R 770 /var/www/html/
25 | sudo a2enmod cgi
26 | sudo service apache2 restart
27 |
28 | echo ""
29 | echo "Downloading dashboard..."
30 | sudo wget --no-check-certificate --quiet --output-document $CGIDIR/dashboard.py https://github.com/autopower/thermeq3/raw/master/install/dashboard/dashboard.py
31 | if [ $? -ne 0 ]; then
32 | echo "Error during downloading dashboard: $?"
33 | exit $?
34 | fi
35 |
36 | echo "Creating dash file"
37 | echo "#!/bin/sh
38 | /usr/bin/env python $CGIDIR/dashboard.py" > ~/dash
39 | echo " - chmod +x"
40 | sudo chmod +x ~/dash
41 | echo " - move file"
42 | sudo mv ~/dash $CGIDIR/dash.sh
43 | echo " - replace ip:port string"
44 | sudo sed -i -e 's/localhost:8180/localhost/g' /usr/lib/cgi-bin/dashboard.py
45 |
46 | echo "Modyfying apache config files"
47 | echo ""
48 | if ! grep -Fq 'AddHandler cgi-script .sh' /etc/apache2/conf-available/serve-cgi-bin.conf ; then
49 | echo " - add .sh handler in cgi-bin"
50 | sudo sed -i '//a AddHandler cgi-script .sh' /etc/apache2/conf-available/serve-cgi-bin.conf
51 | fi
52 | if ! grep -Fq '#Include conf-available\/serve-cgi-bin.conf' /etc/apache2/sites-available/000-default.conf ; then
53 | echo " - include serve cgi-bin config file"
54 | sudo sed -i 's/#Include conf-available\/serve-cgi-bin.conf/Include conf-available\/serve-cgi-bin.conf/g' /etc/apache2/sites-available/000-default.conf
55 | fi
56 | echo "Dashboard succesfully installed."
57 |
--------------------------------------------------------------------------------
/obsolete/lib/config.py:
--------------------------------------------------------------------------------
1 | import os
2 | import json
3 |
4 |
5 | def load_old(old_config_file, new_config_file):
6 | cf_1 = ["self.devname", "self.max_ip", "self.fromaddr", "self.toaddr", "self.mailserver", "self.mailport",
7 | "self.frompwd", "self.owm_api_key", "self.location", "self.extport"]
8 | cf_2 = ["self.device_name", "self.max_ip", "self.from_addr", "self.to_addr", "self.mail_server", "self.mail_port",
9 | "self.from_pwd", "self.owm_api_key", "self.yahoo_location", "self.ext_port"]
10 | ncf = {}
11 | result = 0xFF
12 | if os.path.exists(old_config_file):
13 | try:
14 | f = open(old_config_file, "r")
15 | except IOError:
16 | result = 1
17 | else:
18 | num = 0
19 | for line in f:
20 | is_comment = line.find('#')
21 | if is_comment == 0:
22 | pass
23 | else:
24 | if is_comment > 0:
25 | line = line[:-is_comment]
26 | w = line.split("=")
27 | wr = w[0].rstrip()
28 | if not w[0] == "\n":
29 | if "toaddr" in wr:
30 | wv = w[1].lstrip().rstrip()
31 | else:
32 | wv = w[1].lstrip().rstrip().replace('"', '')
33 | if wr in cf_1:
34 | num += 1
35 | idx = cf_1.index(wr)
36 | ncf.update({cf_2[idx].replace("self.", ""): str(wv)})
37 | if num < len(cf_1):
38 | # some commands are missing
39 | result = 2
40 | else:
41 | # everything is ok
42 | result = 3
43 | f.close()
44 | try:
45 | f = open(new_config_file, "w")
46 | except IOError:
47 | result = 4
48 | else:
49 | json.dump(ncf, f)
50 | f.close()
51 | result = 0
52 | return result
53 |
54 |
55 | def load(config_file):
56 | f = None
57 | result = {}
58 | try:
59 | f = open(config_file, "r")
60 | except IOError:
61 | pass
62 | else:
63 | if f is not None:
64 | result = json.load(f)
65 | finally:
66 | if f is not None:
67 | f.close()
68 | return result
69 |
--------------------------------------------------------------------------------
/obsolete/lib/secweb.py:
--------------------------------------------------------------------------------
1 | import logmsg
2 | import os
3 | import errno
4 |
5 |
6 | sw = None
7 |
8 |
9 | class SecWeb(object):
10 | def __init__(self):
11 | self.location = {}
12 |
13 |
14 | #
15 | # Global module functions
16 | #
17 | def init(location):
18 | """
19 | Setup variables
20 | :param location: where is secondary web directory
21 | :return: nothing
22 | """
23 | global sw
24 | sw = SecWeb()
25 | sw.location = {
26 | "status": str(location + "www/status.json"),
27 | "owl": str(location + "www/owl.json"),
28 | "nice": str(location + "www/nice.html"),
29 | "bridge": str(location + "www/bridge.json"),
30 | "loc": str(location + "www/location.json")}
31 | # check if exists directory for secondary web, if needed, create
32 | try:
33 | os.makedirs(location + "www")
34 | except OSError as exception:
35 | if exception.errno != errno.EEXIST:
36 | raise
37 |
38 |
39 | def write(cw, message):
40 | """
41 | Save message to file which is in secondary web directory
42 | :param message: message or string to write to file
43 | :param cw: string, selector what to save
44 | """
45 | global sw
46 | if cw in sw.location:
47 | fn = sw.location[str(cw)]
48 | try:
49 | swf = open(fn, "w")
50 | except IOError as e:
51 | logmsg.update("Error opening file " + fn + "! I/O error({0}): {1}".format(e.errno, e.strerror))
52 | except EnvironmentError:
53 | logmsg.update("Environment error while opening " + fn + "!", 'E')
54 | else:
55 | try:
56 | swf.write(str(message))
57 | except EnvironmentError:
58 | logmsg.update("Environment error while writing " + fn + "!", 'E')
59 | swf.close()
60 | else:
61 | logmsg.update("Wrong target [" + str(cw) + "] for saving file!", 'E')
62 |
63 |
64 | def nice(message):
65 | message.replace("\n", " ")
66 | message.replace("\t", " ")
67 | write("nice", "\n\nStatus\n\n
" + message + "
\n\n")
68 |
69 |
70 | def save_location(location):
71 | global sw
72 | try:
73 | f = open(sw.location["loc"], "w")
74 | except IOError:
75 | logmsg.update("IOError during opening location file for writing!", 'E')
76 | f.write(str({"location":str(location)}))
77 | f.close()
78 |
--------------------------------------------------------------------------------
/obsolete/lib/support.py:
--------------------------------------------------------------------------------
1 | import platform
2 | import os
3 | import datetime
4 | import urllib2
5 |
6 |
7 | run_target = ""
8 |
9 |
10 | def guess_platform():
11 | """
12 | :return: Boolean
13 | """
14 | global run_target
15 | gos = str(platform.platform()).upper()
16 | target = "rpi"
17 | if "WINDOWS" in gos:
18 | target = "win"
19 | elif "LINUX" in gos:
20 | gm = str(platform.machine()).upper()
21 | if "MIPS" in gm:
22 | target = "yun"
23 | elif "ARM" in gm:
24 | target = "rpi"
25 | run_target = target
26 |
27 |
28 | def is_yun():
29 | """
30 | Return True if platform is yun
31 | :return: Boolean
32 | """
33 | global run_target
34 | if run_target == "yun":
35 | return True
36 | else:
37 | return False
38 |
39 |
40 | def is_rpi():
41 | """
42 | Return True if platform is rpi
43 | :return: Boolean
44 | """
45 | global run_target
46 | if run_target == "rpi":
47 | return True
48 | else:
49 | return False
50 |
51 |
52 | def is_win():
53 | """
54 | Return True if platform is win
55 | :return: Boolean
56 | """
57 | global run_target
58 | if run_target == "win":
59 | return True
60 | else:
61 | return False
62 |
63 |
64 | def get_uptime():
65 | if os.name != "nt":
66 | with open("/proc/uptime", "r") as f:
67 | uptime_seconds = float(f.readline().split()[0])
68 | return_str = str(datetime.timedelta(seconds=uptime_seconds)).split(".")[0]
69 | else:
70 | uptime = os.popen('systeminfo', 'r')
71 | # obfuscate warning
72 | data = uptime.readlines()
73 | data += ""
74 | uptime.close()
75 | return_str = str(0)
76 | return return_str
77 |
78 |
79 | def is_empty(var):
80 | if var == "" or var is None or var == "None":
81 | return True
82 | else:
83 | return False
84 |
85 |
86 | def io_error(err):
87 | """
88 | :param err: Exception handler
89 | :return: string
90 | """
91 | return "I/O error({0}): {1}".format(err.errno, err.strerror)
92 |
93 |
94 | def call_home(selector):
95 | if selector == "apprun":
96 | url = "https://www.google-analytics.com/collect?v=1&t=event&tid=UA-106611241-1&cid=1&ec=App&ea=Run"
97 | elif selector == "applive":
98 | url = "https://www.google-analytics.com/collect?v=1&t=event&tid=UA-106611241-1&cid=1&ec=App&ea=Live"
99 | else:
100 | url = "https://www.google-analytics.com/collect?v=1&t=event&tid=UA-106611241-1&cid=1&ec=App&ea=Other"
101 | try:
102 | urllib2.urlopen(url).read()
103 | except Exception:
104 | pass
105 |
--------------------------------------------------------------------------------
/obsolete/lib/logmsg.py:
--------------------------------------------------------------------------------
1 | import os
2 | import logging
3 | import logging.handlers
4 | import inspect
5 |
6 | log_messages = []
7 | logs = ['I', 'D', 'E']
8 | logger = None
9 |
10 |
11 | def update(message, log='D'):
12 | """
13 | Update list with message and log level
14 | :param message: string
15 | :param log: char, log selector
16 | :return:
17 | """
18 | global log_messages, logs
19 | if log in logs:
20 | log_messages.append([log, message])
21 | else:
22 | log_messages.append(['E', message])
23 | flush()
24 |
25 |
26 | def debug(*args):
27 | """
28 | Converts arguments to strings, concat them and update log
29 | :param args: argument list
30 | :return: nothing
31 | """
32 | ln = len(args)
33 | if ln > 0:
34 | tmp_str = "## " + str(inspect.stack()[1][3]) + " ## "
35 | for i in range(0, ln):
36 | tmp_str += str(args[i])
37 | update(tmp_str, 'D')
38 |
39 |
40 | def flush():
41 | """
42 | Flush log messages
43 | :return: nothing
44 | """
45 | global log_messages, logger
46 | # if list is not empty
47 | if log_messages:
48 | for k in log_messages:
49 | if k[0] == 'E':
50 | logger.error(k[1])
51 | elif k[0] == 'D':
52 | logger.debug(k[1])
53 | elif k[0] == 'I':
54 | logger.info(k[1])
55 | elif k[0] == 'C':
56 | logger.critical(k[1])
57 | else:
58 | logger.error("Wrong level: " + str(k[0]) + " message: " + str(k[1]))
59 | log_messages = []
60 |
61 |
62 | def start(log_filename):
63 | """
64 | Start writing to time rotated log file
65 | :param log_filename: string
66 | :return:
67 | """
68 | global logger
69 | logger = logging.getLogger("thermeq3")
70 | logger.setLevel(logging.DEBUG)
71 |
72 | try:
73 | fh = logging.handlers.TimedRotatingFileHandler(log_filename, when="W0", interval=4, backupCount=12)
74 | except Exception:
75 | print log_filename
76 | raise
77 | fh.setLevel(logging.DEBUG)
78 |
79 | formatter = logging.Formatter("%(asctime)s [%(levelname)s] %(message)s", datefmt="%Y/%m/%d %H:%M:%S")
80 | fh.setFormatter(formatter)
81 | logger.addHandler(fh)
82 |
83 | logger.info("Started with PID=" + str(os.getpid()))
84 |
85 |
86 | def level(selector):
87 | """
88 | Changes log level
89 | :param selector: char
90 | :return: nothing
91 | """
92 | global logger
93 | if selector == 'D':
94 | logger.setLevel(logging.DEBUG)
95 | elif selector == 'I':
96 | logger.setLevel(logging.INFO)
97 |
98 |
99 | def stop():
100 | """
101 | Stops logging
102 | :return: nothing
103 | """
104 | global logger
105 | logger.close()
106 |
--------------------------------------------------------------------------------
/obsolete/install/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/ash
2 | if [ $# -lt 1 ]; then
3 | echo "Usage: install.sh "
4 | exit 1
5 | fi
6 |
7 | echo "Preparing..."
8 | echo "opkg update"
9 | opkg update --verbosity=0
10 | if [ $? -ne 0 ]; then
11 | echo "Error during opkg update: $?"
12 | exit $?
13 | fi
14 |
15 | mkdir /root/thermeq3-install
16 | echo Downloading thermeq3 app
17 | wget --no-check-certificate --quiet --output-document /root/nsm.py https://github.com/autopower/thermeq3/raw/master/install/nsm.py
18 | if [ $? -ne 0 ]; then
19 | echo "Error during downloading thermeq3 app: $?"
20 | exit $?
21 | fi
22 |
23 | echo Downloading thermeq3 config file
24 | wget --no-check-certificate --quiet --output-document /root/config.py https://github.com/autopower/thermeq3/raw/master/install/config.py
25 | if [ $? -ne 0 ]; then
26 | echo "Error during downloading thermeq3 config file: $?"
27 | exit $?
28 | fi
29 |
30 | echo "Installing libraries"
31 | opkg install python-openssl --verbosity=0
32 | if [ $? -ne 0 ]; then
33 | echo "Error during installing openssl library. Error: $?"
34 | exit $?
35 | fi
36 | opkg install python-expat --verbosity=0
37 | if [ $? -ne 0 ]; then
38 | echo "Error during installing expat library. Error: $?"
39 | exit $?
40 | fi
41 |
42 | if [ -d /mnt/sda1 ]; then
43 | DIR=/mnt/sda1
44 | else
45 | if [ -d /mnt/sdb1 ]; then
46 | DIR=/mnt/sdb1
47 | else
48 | echo "Please mount USB or SD card!"
49 | exit 1
50 | fi
51 | fi
52 | echo "Using $DIR as storage path."
53 |
54 | if ! grep -q "0.0.0.0:8180" /etc/config/uhttpd; then
55 | echo "Backing up uhttpd configuration..."
56 | mkdir /root/backup
57 | cp /etc/config/uhttpd /root/backup/uhttpd.old
58 | echo "Modifying uhttpd configuration..."
59 | echo "config uhttpd secondary
60 | list listen_http 0.0.0.0:8180
61 | option home $DIR/www
62 | option cgi_prefix /cgi-bin
63 | option max_requests 2
64 | option script_timeout 10
65 | option network_timeout 10
66 | option tcp_keepalive 1
67 | " >> /etc/config/uhttpd
68 | echo "Restarting uhttpd..."
69 | /etc/init.d/uhttpd restart
70 | fi
71 |
72 | echo "Creating directories and cgi scripts"
73 | mkdir -p $DIR/www
74 | cd $DIR/www
75 | mkdir -p cgi-bin
76 | cd cgi-bin
77 |
78 | echo "#!/bin/sh
79 | echo \"Content-type: application/json\"
80 | echo \"\"
81 | cat $DIR/www/status.xml" > status
82 | echo "#!/bin/sh
83 | echo \"Content-type: application/json\"
84 | echo \"\"
85 | cat $DIR/www/owl.xml" > owl
86 | echo "#!/bin/sh
87 | echo \"Content-type: text/html\"
88 | echo \"\"
89 | cat $DIR/www/nice.html" > nice
90 | chmod +x status
91 | chmod +x owl
92 | chmod +x nice
93 |
94 | echo "Installing scripts with $1 as device name and $DIR as target directory"
95 | echo "tail -n 50 $DIR/$1.log" > /root/ct
96 | echo "cat $DIR/$1_error.log" > /root/err
97 | echo "ps|grep python" > /root/psg
98 | chmod +x /root/ct
99 | chmod +x /root/err
100 | chmod +x /root/psg
101 | echo "Please edit config.py file!"
--------------------------------------------------------------------------------
/obsolete/install/README.md:
--------------------------------------------------------------------------------
1 | # thermeq3
2 | ### Install application
3 | Access yún via ssh (e.g. Windows users can use putty)
4 | * Update `opkg`: `opkg update`
5 | * Update `wget`: `opkg upgrade wget`
6 | * Install `thermeq3`, please look below for help
7 | * Run the installer script: `/root/install.sh ` (if you are upgrading from V231-, run `/root/upgrade.sh`), for example `/root/install.sh boilerstarter`, this `boilerstarter` name will be used as
8 | device name
9 | * **Edit required values in the config file** Please take a look below how to modify config file.
10 | * You'll need SMTP server details and [Open Weather Map API key](http://openweathermap.org/appid) (sign-up is free).
11 |
12 | ### I want to install version below 231
13 | For v200+, use `wget --no-check-certificate --quiet --output-document /root/install.sh https://raw.githubusercontent.com/autopower/thermeq3/master/install/current/install.sh;chmod +x /root/upgrade.sh`
14 |
15 | ### I want to install v150
16 | Versions below 200 are obsolete! For v150, use `wget --no-check-certificate --quiet --output-document /root/install.sh https://raw.githubusercontent.com/autopower/thermeq3/master/install/obsolete/install.sh;chmod +x /root/upgrade.sh`
17 |
18 | ### Upgrading from V2xx to V231+
19 | **If you are upgrading from version below V231** and you have working installation, please use [this script](https://github.com/autopower/thermeq3/tree/master/install/current/upgrade.sh) or `wget --no-check-certificate --quiet --output-document /root/upgrade.sh https://raw.githubusercontent.com/autopower/thermeq3/master/install/current/upgrade.sh;chmod +x /root/upgrade.sh`.
20 |
21 | ### Modifying config file
22 | #### V199-
23 | You can edit `config.py` file with default editor `vi`. If you are no familiar with `vi` (try [this man](https://www.freebsd.org/cgi/man.cgi?vi)), you can use your favourite editor on your platform and transfer file via ftp/scp. For example if you are using windows, you can use [pspad](http://www.pspad.com/en/) and transfer file via [winscp](https://winscp.net/eng/index.php).
24 | * `stp.max_ip = "192.168.0.10"` IP address of MAX! cube
25 | * `stp.fromaddr = "devices@foo.local"` from, user name
26 | * `stp.toaddr = "user@foo.local"` to email
27 | * `stp.mailserver = "mail.foo.local"` via this server
28 | * `stp.mailport = 25` on this port
29 | * `stp.frompwd = "this.is.password"` login with this password
30 | * `stp.devname = "hellmostat"` device name
31 | * `stp.timeout = 10` timeout in secods, used in communicating with MAX! Cube and as a sleep time for flushing msg queue, set to similar value as `unsigned long interval` in arduino sketch
32 | * `stp.extport = 29080` external port, this is the port (typically) on firewall where NAT is defined (so you can mute thermeq3 from internet), please setup your firewall/router to such scenario
33 | * `stp.owm_api_key = "your owm api key"` this is API key for OWM service
34 |
35 | #### V200 to V230
36 | For V200+ `stp.` is replaced with `self.setup.` or `self.` so `stp.max_ip` becomes `self.setup.max_ip`.
37 |
38 | #### V231 to V249
39 | **Version 231+ automatically reads old config.py file format (plain python code) and converts it to JSON format.**
40 | If you are using V231+ please use current config file in JSON format with name `thermeq.json`
41 |
42 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at autopowerdevice@gmail.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/obsolete/install/V231/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/ash
2 | if [ $# -lt 1 ]; then
3 | echo "Usage: install.sh "
4 | exit 1
5 | fi
6 |
7 | echo "Preparing..."
8 | echo "opkg update"
9 | opkg update --verbosity=0
10 | if [ $? -ne 0 ]; then
11 | echo "Error during opkg update: $?"
12 | exit $?
13 | fi
14 |
15 | echo "Installing zip"
16 | opkg install unzip --verbosity=0
17 | if [ $? -ne 0 ]; then
18 | echo "Error during installing unzip. Error: $?"
19 | exit $?
20 | fi
21 |
22 | mkdir /root/thermeq3-install
23 | echo Downloading thermeq3 app
24 | wget --no-check-certificate --quiet --output-document /root/thermeq3-install/thermeq3.zip https://github.com/autopower/thermeq3/raw/master/install/current/thermeq3.zip
25 | if [ $? -ne 0 ]; then
26 | echo "Error during downloading thermeq3 app: $?"
27 | exit $?
28 | fi
29 | mkdir /root/thermeq3
30 | echo "Unzipping app"
31 | unzip -q /root/thermeq3-install/thermeq3.zip -d /root/thermeq3
32 | if [ $? -ne 0 ]; then
33 | echo "Error during unzipping thermeq3 app: $?"
34 | exit $?
35 | fi
36 |
37 | echo Downloading thermeq3 config file
38 | wget --no-check-certificate --quiet --output-document /root/config.py https://github.com/autopower/thermeq3/raw/master/install/current/config.py
39 | if [ $? -ne 0 ]; then
40 | echo "Error during downloading thermeq3 config file: $?"
41 | exit $?
42 | fi
43 |
44 | echo "Installing libraries"
45 | opkg install python-openssl --verbosity=0
46 | if [ $? -ne 0 ]; then
47 | echo "Error during installing openssl library. Error: $?"
48 | exit $?
49 | fi
50 | opkg install python-expat --verbosity=0
51 | if [ $? -ne 0 ]; then
52 | echo "Error during installing expat library. Error: $?"
53 | exit $?
54 | fi
55 |
56 | if [ -d /mnt/sda1 ]; then
57 | DIR=/mnt/sda1
58 | else
59 | if [ -d /mnt/sdb1 ]; then
60 | DIR=/mnt/sdb1
61 | else
62 | echo "Please mount USB or SD card!"
63 | exit 1
64 | fi
65 | fi
66 | echo "Using $DIR as storage path."
67 |
68 | if ! grep -q "0.0.0.0:8180" /etc/config/uhttpd; then
69 | echo "Backing up uhttpd configuration..."
70 | mkdir /root/backup
71 | cp /etc/config/uhttpd /root/backup/uhttpd.old
72 | echo "Modifying uhttpd configuration..."
73 | echo "config uhttpd secondary
74 | list listen_http 0.0.0.0:8180
75 | option home $DIR/www
76 | option cgi_prefix /cgi-bin
77 | option max_requests 2
78 | option script_timeout 10
79 | option network_timeout 10
80 | option tcp_keepalive 1
81 | " >> /etc/config/uhttpd
82 | echo "Restarting uhttpd..."
83 | /etc/init.d/uhttpd restart
84 | fi
85 |
86 | echo "Creating directories and cgi scripts"
87 | mkdir -p $DIR/www
88 | cd $DIR/www
89 | mkdir -p $DIR/csv
90 | cd $DIR/www
91 | mkdir -p cgi-bin
92 | cd cgi-bin
93 |
94 | echo "#!/bin/sh
95 | echo \"Content-type: application/json\"
96 | echo \"\"
97 | cat $DIR/www/status.xml" > status
98 | echo "#!/bin/sh
99 | echo \"Content-type: application/json\"
100 | echo \"\"
101 | cat $DIR/www/owl.xml" > owl
102 | echo "#!/bin/sh
103 | echo \"Content-type: text/html\"
104 | echo \"\"
105 | cat $DIR/www/nice.html" > nice
106 | chmod +x status
107 | chmod +x owl
108 | chmod +x nice
109 |
110 | echo "Creating nsm.py compatibility file"
111 | echo "#!/usr/bin/env python
112 | import sys
113 |
114 | sys.path.insert(0, \"/root/thermeq3/\")
115 | execfile(\"/root/thermeq3/nsm.py\")
116 | " > /root/nsm.py
117 |
118 | echo "Installing scripts with $1 as device name and $DIR as target directory"
119 | echo "tail -n 50 $DIR/$1.log" > /root/ct
120 | echo "cat $DIR/$1_error.log" > /root/err
121 | echo "ps|grep python" > /root/psg
122 | chmod +x /root/ct
123 | chmod +x /root/err
124 | chmod +x /root/psg
125 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #################
2 | ## Eclipse
3 | #################
4 |
5 | *.pydevproject
6 | .project
7 | .metadata
8 | bin/
9 | tmp/
10 | *.tmp
11 | *.bak
12 | *.swp
13 | *~.nib
14 | local.properties
15 | .classpath
16 | .settings/
17 | .loadpath
18 |
19 | # External tool builders
20 | .externalToolBuilders/
21 |
22 | # Locally stored "Eclipse launch configurations"
23 | *.launch
24 |
25 | # CDT-specific
26 | .cproject
27 |
28 | # PDT-specific
29 | .buildpath
30 |
31 |
32 | #################
33 | ## Visual Studio
34 | #################
35 |
36 | ## Ignore Visual Studio temporary files, build results, and
37 | ## files generated by popular Visual Studio add-ons.
38 |
39 | # User-specific files
40 | *.suo
41 | *.user
42 | *.sln.docstates
43 |
44 | # Build results
45 |
46 | [Dd]ebug/
47 | [Rr]elease/
48 | x64/
49 | build/
50 | [Bb]in/
51 | [Oo]bj/
52 |
53 | # MSTest test Results
54 | [Tt]est[Rr]esult*/
55 | [Bb]uild[Ll]og.*
56 |
57 | *_i.c
58 | *_p.c
59 | *.ilk
60 | *.meta
61 | *.obj
62 | *.pch
63 | *.pdb
64 | *.pgc
65 | *.pgd
66 | *.rsp
67 | *.sbr
68 | *.tlb
69 | *.tli
70 | *.tlh
71 | *.tmp
72 | *.tmp_proj
73 | *.log
74 | *.vspscc
75 | *.vssscc
76 | .builds
77 | *.pidb
78 | *.log
79 | *.scc
80 |
81 | # Visual C++ cache files
82 | ipch/
83 | *.aps
84 | *.ncb
85 | *.opensdf
86 | *.sdf
87 | *.cachefile
88 |
89 | # Visual Studio profiler
90 | *.psess
91 | *.vsp
92 | *.vspx
93 |
94 | # Guidance Automation Toolkit
95 | *.gpState
96 |
97 | # ReSharper is a .NET coding add-in
98 | _ReSharper*/
99 | *.[Rr]e[Ss]harper
100 |
101 | # TeamCity is a build add-in
102 | _TeamCity*
103 |
104 | # DotCover is a Code Coverage Tool
105 | *.dotCover
106 |
107 | # NCrunch
108 | *.ncrunch*
109 | .*crunch*.local.xml
110 |
111 | # Installshield output folder
112 | [Ee]xpress/
113 |
114 | # DocProject is a documentation generator add-in
115 | DocProject/buildhelp/
116 | DocProject/Help/*.HxT
117 | DocProject/Help/*.HxC
118 | DocProject/Help/*.hhc
119 | DocProject/Help/*.hhk
120 | DocProject/Help/*.hhp
121 | DocProject/Help/Html2
122 | DocProject/Help/html
123 |
124 | # Click-Once directory
125 | publish/
126 |
127 | # Publish Web Output
128 | *.Publish.xml
129 | *.pubxml
130 |
131 | # NuGet Packages Directory
132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
133 | #packages/
134 |
135 | # Windows Azure Build Output
136 | csx
137 | *.build.csdef
138 |
139 | # Windows Store app package directory
140 | AppPackages/
141 |
142 | # Others
143 | sql/
144 | *.Cache
145 | ClientBin/
146 | [Ss]tyle[Cc]op.*
147 | ~$*
148 | *~
149 | *.dbmdl
150 | *.[Pp]ublish.xml
151 | *.pfx
152 | *.publishsettings
153 |
154 | # RIA/Silverlight projects
155 | Generated_Code/
156 |
157 | # Backup & report files from converting an old project file to a newer
158 | # Visual Studio version. Backup files are not needed, because we have git ;-)
159 | _UpgradeReport_Files/
160 | Backup*/
161 | UpgradeLog*.XML
162 | UpgradeLog*.htm
163 |
164 | # SQL Server files
165 | App_Data/*.mdf
166 | App_Data/*.ldf
167 |
168 | #############
169 | ## Windows detritus
170 | #############
171 |
172 | # Windows image file caches
173 | Thumbs.db
174 | ehthumbs.db
175 |
176 | # Folder config file
177 | Desktop.ini
178 |
179 | # Recycle Bin used on file shares
180 | $RECYCLE.BIN/
181 |
182 | # Mac crap
183 | .DS_Store
184 |
185 |
186 | #############
187 | ## Python
188 | #############
189 |
190 | *.py[co]
191 |
192 | # Packages
193 | *.egg
194 | *.egg-info
195 | dist/
196 | build/
197 | eggs/
198 | parts/
199 | var/
200 | sdist/
201 | develop-eggs/
202 | .installed.cfg
203 |
204 | # Installer logs
205 | pip-log.txt
206 |
207 | # Unit test / coverage reports
208 | .coverage
209 | .tox
210 |
211 | #Translations
212 | *.mo
213 |
214 | #Mr Developer
215 | .mr.developer.cfg
216 |
--------------------------------------------------------------------------------
/obsolete/lib/csvfile.py:
--------------------------------------------------------------------------------
1 | import os
2 | import time
3 | import logmsg
4 |
5 |
6 | class CsvObject(object):
7 | def __init__(self):
8 | self.file = ""
9 | self.handle = None
10 | self.state = False
11 | self.place = ""
12 | self.dev_name = ""
13 | self._buffer = ""
14 |
15 | def __repr__(self):
16 | return str(self.__class__) + ": " + str(self.__dict__)
17 |
18 | def __str__(self):
19 | return str(self.__class__) + ": " + str(self.__dict__)
20 |
21 | def is_init(self):
22 | return self.file == "" and self.place == "" and self.dev_name == ""
23 |
24 | def open(self):
25 | if self.is_init():
26 | raise NameError("Wrong init!")
27 | if os.path.exists(self.file):
28 | try:
29 | os.rename(self.file,
30 | self.place + self.dev_name + "_" + time.strftime("%Y%m%d-%H%M%S", time.localtime()) + ".csv")
31 | except Exception:
32 | pass
33 | try:
34 | self.handle = open(self.file, "a")
35 | except IOError:
36 | this_path = os.path.dirname(self.file)
37 | if not os.path.exists(this_path):
38 | try:
39 | os.makedirs(this_path)
40 | except Exception:
41 | logmsg.update("Can't create directory for CSV files (" + str(this_path) + ")")
42 | raise
43 | except Exception:
44 | logmsg.update("Can't open CSV file: " + str(self.file))
45 | raise
46 | else:
47 | self.state = True
48 |
49 | def close(self):
50 | try:
51 | self.handle.flush()
52 | except:
53 | pass
54 |
55 | try:
56 | os.fsync(self.handle.fileno())
57 | except:
58 | pass
59 |
60 | try:
61 | self.handle.close()
62 | except Exception:
63 | logmsg.update("Can't close CSV file!")
64 | else:
65 | self.state = False
66 |
67 | def add(self, text):
68 | self._buffer += text + ","
69 |
70 | def write(self):
71 | if self._buffer[-1:] == ',':
72 | self._buffer = self._buffer[:-1]
73 | self.handle.write(self._buffer + "\n")
74 | self.handle.flush()
75 | self._buffer = ""
76 |
77 |
78 | csv = CsvObject()
79 |
80 |
81 | def is_init():
82 | """
83 | Is CSV initalized?
84 | :return: boolean
85 | """
86 | global csv
87 | return csv.state
88 |
89 |
90 | def init(place, dev_name):
91 | """
92 | Init CSV variables and open CSV file
93 | :param place:
94 | :param dev_name:
95 | :return: boolean
96 | """
97 | global csv
98 | if not place == "":
99 | if place[-1:] != '/':
100 | place += '/'
101 | place += "csv/"
102 | csv.place = place
103 | else:
104 | return False
105 | if not dev_name == "":
106 | csv.dev_name = dev_name
107 | else:
108 | return False
109 | csv.file = place + dev_name + ".csv"
110 | csv.state = True
111 | csv.open()
112 |
113 |
114 | def close():
115 | global csv
116 | """
117 | Close CSV file
118 | :return: nothing
119 | """
120 | csv.close()
121 |
122 |
123 | def write(*args):
124 | """
125 | Write arguments to CSV file
126 | :param args: arguments
127 | :return: nothing
128 | """
129 | global csv
130 | if not is_init:
131 | csv.open()
132 | ln = len(args)
133 | if ln > 0:
134 | for i in range(0, ln):
135 | if args[i] == "\n":
136 | csv.write()
137 | else:
138 | csv.add(str(args[i]))
139 |
--------------------------------------------------------------------------------
/obsolete/install/alpha_Yun_Rev2/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/ash
2 | if [ $# -lt 1 ]; then
3 | echo "Usage: install.sh "
4 | exit 1
5 | fi
6 |
7 | echo "Preparing..."
8 | echo "opkg update"
9 | opkg update --verbosity=0
10 | if [ $? -ne 0 ]; then
11 | echo "Error during opkg update: $?"
12 | exit $?
13 | fi
14 |
15 | echo "Installing zip"
16 | opkg install unzip --verbosity=0
17 | if [ $? -ne 0 ]; then
18 | echo "Error during installing unzip. Error: $?"
19 | exit $?
20 | fi
21 |
22 | mkdir /root/thermeq3-install
23 | echo Downloading thermeq3 app
24 | wget --no-check-certificate --quiet -O /root/thermeq3-install/thermeq3.zip https://github.com/autopower/thermeq3/raw/master/install/current/thermeq3.zip
25 | if [ $? -ne 0 ]; then
26 | echo "Error during downloading thermeq3 app: $?"
27 | exit $?
28 | fi
29 | mkdir /root/thermeq3
30 | echo "Unzipping app"
31 | unzip -q /root/thermeq3-install/thermeq3.zip -d /root/thermeq3
32 | if [ $? -ne 0 ]; then
33 | echo "Error during unzipping thermeq3 app: $?"
34 | exit $?
35 | fi
36 |
37 | echo "Installing libraries"
38 | opkg install python-openssl --verbosity=0
39 | if [ $? -ne 0 ]; then
40 | echo "Error during installing openssl library. Error: $?"
41 | exit $?
42 | fi
43 |
44 | if [ -d /mnt/sda1 ]; then
45 | DIR=/mnt/sda1
46 | else
47 | if [ -d /mnt/sdb1 ]; then
48 | DIR=/mnt/sdb1
49 | else
50 | echo "Please mount USB or SD card!"
51 | exit 1
52 | fi
53 | fi
54 | echo "Using $DIR as storage path."
55 |
56 | if ! grep -q "0.0.0.0:8180" /etc/config/uhttpd; then
57 | echo "Backing up uhttpd configuration..."
58 | mkdir /root/backup
59 | cp /etc/config/uhttpd /root/backup/uhttpd.old
60 | echo "Modifying uhttpd configuration..."
61 | echo "config uhttpd secondary
62 | list listen_http 0.0.0.0:8180
63 | option home $DIR/www
64 | option cgi_prefix /cgi-bin
65 | option max_requests 2
66 | option script_timeout 10
67 | option network_timeout 10
68 | option tcp_keepalive 1
69 | " >> /etc/config/uhttpd
70 | echo "Restarting uhttpd..."
71 | /etc/init.d/uhttpd restart
72 | fi
73 |
74 | echo "Creating directories and cgi scripts"
75 | mkdir -p $DIR/www
76 | cd $DIR/www
77 | mkdir -p $DIR/csv
78 | cd $DIR/www
79 | mkdir -p cgi-bin
80 | cd cgi-bin
81 |
82 | echo "Creating nsm.py compatibility file"
83 | echo "#!/usr/bin/env python
84 | import sys
85 | sys.path.insert(0, \"/root/thermeq3/\")
86 | execfile(\"/root/thermeq3/nsm.py\")
87 | " > /root/nsm.py
88 |
89 | echo "Installing scripts with $1 as device name and $DIR as target directory"
90 | echo "tail -n 50 $DIR/$1.log" > /root/ct
91 | echo "cat $DIR/$1_error.log" > /root/err
92 | echo "ps|grep python" > /root/psg
93 | echo "ps -ef | grep nsm.py | grep -v grep | awk '{print $1}' | xargs kill -9" > /root/killnsm
94 | chmod +x /root/ct
95 | chmod +x /root/err
96 | chmod +x /root/psg
97 | chmod +x /root/killnsm
98 |
99 | echo "Downloading interactive config"
100 | wget --no-check-certificate --quiet -O /root/config_me.py https://raw.githubusercontent.com/autopower/thermeq3/master/install/current/config_me.py;chmod +x /root/config_me.py
101 | if [ $? -ne 0 ]; then
102 | echo "Error during downloading config app: $?"
103 | exit $?
104 | fi
105 | echo "Downloading dashboard install script"
106 | wget --no-check-certificate --quiet -O /root/install-dash.sh https://raw.githubusercontent.com/autopower/thermeq3/master/install/dashboard/install-dash.sh;chmod +x /root/install-dash.sh
107 | if [ $? -ne 0 ]; then
108 | echo "Error during downloading dashboard install script: $?"
109 | exit $?
110 | fi
111 | echo "Dashboard install..."
112 | /root/install-dash.sh
113 | echo "Interactive config..."
114 | /root/config_me.py
115 | if [ -d /root/location.json]; then
116 | mv /root/location.json $DIR/www/location.json
117 | else
118 | echo "Can't find file. Please make location.json file for dashboard!"
119 | fi
120 |
--------------------------------------------------------------------------------
/install/RPi/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | if [ $# -lt 1 ]; then
3 | echo "Usage: install.sh "
4 | exit 1
5 | fi
6 |
7 | BASE_DIR=/home/pi/thermeq3
8 | mkdir -p $BASE_DIR
9 | mkdir -p $BASE_DIR/install
10 |
11 | echo "Downloading thermeq3 app"
12 | wget --no-check-certificate --quiet --output-document $BASE_DIR/install/thermeq3.zip https://github.com/autopower/thermeq3/raw/master/install/RPi/thermeq3.zip
13 | if [ $? -ne 0 ]; then
14 | echo "Error during downloading thermeq3 app: $?"
15 | exit $?
16 | fi
17 | mkdir $BASE_DIR/code
18 | echo "Unzipping app"
19 | unzip -q -o $BASE_DIR/install/thermeq3.zip -d $BASE_DIR/code
20 | if [ $? -ne 0 ]; then
21 | echo "Error during unzipping thermeq3 app: $?"
22 | exit $?
23 | fi
24 |
25 | echo "Installing libraries"
26 | echo "Updating apt-get and upgrading packages"
27 | sudo apt-get update
28 | sudo apt-get upgrade
29 | PKG_OK=$(dpkg-query -W --showformat='${Status}\n' python-openssl|grep "install ok installed")
30 | echo Checking for python-openssl: $PKG_OK
31 | if [ "" == "$PKG_OK" ]; then
32 | echo "No python-openssl. Installing python-openssl"
33 | sudo apt-get --force-yes --yes install python-openssl
34 | if [ $? -ne 0 ]; then
35 | echo "Error during installing openssl library. Error: $?"
36 | fi
37 | exit $?
38 | fi
39 |
40 | echo "Creating nsm.py compatibility file"
41 | echo "#!/usr/bin/env python
42 | import sys
43 | sys.path.insert(0, \"$BASE_DIR/code/\")
44 | execfile(\"$BASE_DIR/code/nsm.py\")
45 | " > $BASE_DIR/nsm.py
46 |
47 | echo "Creating systemd files"
48 | echo "[Unit]
49 | Description=thermeq3 Service
50 | After=multi-user.target
51 |
52 | [Service]
53 | Type=idle
54 | ExecStart=/usr/bin/python /home/pi/thermeq3/nsm.py
55 |
56 | [Install]
57 | WantedBy=multi-user.target" > /home/pi/thermeq3/tmp/thermeq3.service
58 | sudo mv /home/pi/thermeq3/tmp/thermeq3.service /lib/systemd/system/thermeq3.service
59 | sudo chmod 644 /lib/systemd/system/thermeq3.service
60 | sudo systemctl daemon-reload
61 | sudo systemctl enable thermeq3.service
62 |
63 | echo "Installing scripts with $1 as device name and $BASE_DIR as target directory"
64 | echo "tail -n 50 $BASE_DIR/$1.log" > $BASE_DIR/ct
65 | echo "cat $BASE_DIR/$1_error.log" > $BASE_DIR/err
66 | echo "ps|grep python" > $BASE_DIR/psg
67 | echo "ps -ef | grep nsm.py | grep -v grep | awk '{print $1}' | xargs kill -9" > $BASE_DIR/killnsm
68 | chmod +x $BASE_DIR/ct
69 | chmod +x $BASE_DIR/err
70 | chmod +x $BASE_DIR/psg
71 | chmod +x $BASE_DIR/killnsm
72 |
73 | echo "Creating folder for CSV files..."
74 | mkdir -p $BASE_DIR/csv
75 |
76 | echo "Downloading interactive config"
77 | wget --no-check-certificate --quiet --output-document $BASE_DIR/config_me.py https://raw.githubusercontent.com/autopower/thermeq3/master/install/current/config_me.py;chmod +x $BASE_DIR/config_me.py
78 | if [ $? -ne 0 ]; then
79 | echo "Error during downloading config app: $?"
80 | exit $?
81 | fi
82 |
83 | read -p "Install dahsboard? [y/n]" yn
84 | case $yn in
85 | [Yy]*)
86 | echo "Downloading dashboard install script"
87 | wget --no-check-certificate --quiet --output-document $BASE_DIR/install-dash.sh https://raw.githubusercontent.com/autopower/thermeq3/master/install/RPi/install-dash.sh;chmod +x $BASE_DIR/install-dash.sh
88 | if [ $? -ne 0 ]; then
89 | echo "Error during downloading dashboard install script: $?"
90 | exit $?
91 | fi
92 | echo "Running dashboard install..."
93 | $BASE_DIR/install-dash.sh
94 | ;;
95 | esac
96 |
97 | echo "Interactive config..."
98 | $BASE_DIR/config_me.py
99 | if [ -f $BASE_DIR/location.json ]; then
100 | echo "Moving file..."
101 | mv $BASE_DIR/location.json /var/www/html/location.json
102 | else
103 | echo "Can't find file. Please make location.json file for dashboard!"
104 | fi
105 |
106 | read -p "Delete install folder? [y/n]" yn
107 | case $yn in
108 | [Yy]*)
109 | echo "Removing install folder..."
110 | rm -rf $BASE_DIR/install/*
111 | rmdir $BASE_DIR/install
112 | ;;
113 | esac
--------------------------------------------------------------------------------
/obsolete/lib/profiles.py:
--------------------------------------------------------------------------------
1 | import logmsg
2 | import datetime
3 | import time
4 | import bridge
5 |
6 |
7 | class Profile(object):
8 | def __init__(self):
9 | """
10 | Init variables
11 | :rtype: object
12 | """
13 | self.day = []
14 | self.temp = []
15 | self.selected_mode = 0
16 | self.act_mode_idx = 0
17 | self.sit = {}
18 |
19 | def start(self, dt, tt):
20 | self.day = dt
21 | self.temp = tt
22 |
23 |
24 | table = Profile()
25 |
26 |
27 | def check_day_table():
28 | """
29 | :return:
30 | """
31 | global table
32 | if len(table.day) > 1:
33 | for i in range(len(table.day) - 1):
34 | if time.strptime(table.day[i + 1][0], "%H:%M") <= time.strptime(table.day[i][0], "%H:%M"):
35 | logmsg.update("Day mode table is wrong! Using default table!", 'E')
36 | table.day = [["00:00", "23:59", 35, 185, "total", 120, 2]]
37 |
38 |
39 | def time_in_range(start, end, x):
40 | """
41 | :param start:
42 | :param end:
43 | :param x:
44 | :return:
45 | """
46 | today = datetime.date.today()
47 | start = datetime.datetime.combine(today, start)
48 | end = datetime.datetime.combine(today, end)
49 | x = datetime.datetime.combine(today, x)
50 | if end <= start:
51 | end += datetime.timedelta(1) # tomorrow!
52 | if x <= start:
53 | x += datetime.timedelta(1) # tomorrow!
54 | return start <= x <= end
55 |
56 |
57 | def is_time():
58 | """
59 | :return:
60 | """
61 | global table
62 | this_now = datetime.datetime.now().time()
63 | ret_value = -1
64 | for k in table.day:
65 | nf = datetime.datetime.strptime(k[0], "%H:%M").time()
66 | nt = datetime.datetime.strptime(k[1], "%H:%M").time()
67 | if time_in_range(nf, nt, this_now):
68 | ret_value = table.day.index(k)
69 | # logmsg.update("IsTime=" + str(ret_value))
70 | return ret_value
71 |
72 |
73 | def time_mode():
74 | """
75 | :return:
76 | """
77 | global table
78 | # day = [0-from_str, 1-to_str, 2-total or per, 3-mode ("total"/"per"), 4-check interval, 5-valves]
79 | md = is_time()
80 | # logmsg.update("Actual index=" + str(table.act_mode_idx), 'D')
81 | if md != -1:
82 | if md != table.act_mode_idx:
83 | kv = table.day[md]
84 | table.act_mode_idx = md
85 | logmsg.update("Switching day mode to " + str(md) + " = " + str(kv), 'I')
86 | return kv
87 |
88 |
89 | def temp_mode():
90 | """
91 | :return:
92 | """
93 | global table
94 | if None not in table.sit.viewvalues():
95 | c_temp = int(table.sit["current_temp"])
96 | for k in range(0, len(table.temp)):
97 | kv = table.temp[k]
98 | if kv[1] > c_temp >= kv[0]:
99 | table.act_mode_idx = k
100 | logmsg.update("Switching temp mode to " + str(kv[0]) + " ~ " + str(kv[1]), 'I')
101 | return kv
102 | else:
103 | logmsg.update("Weather situation error", 'E')
104 |
105 |
106 | def do(sel_mode, act_idx, sit):
107 | """
108 | Performs day or temp mode selection
109 | :param sel_mode: char, selected mode
110 | :param act_idx: integer, actual index
111 | :param sit: dictionary, weather situation
112 | :return: list
113 | """
114 | # update variables from main code
115 | global table
116 | table.selected_mode = sel_mode
117 | table.act_mode_idx = act_idx
118 | table.sit = sit
119 | tmp_prof = bridge.try_read("profile", True).upper()
120 | kv = []
121 | if tmp_prof != table.selected_mode:
122 | table.selected_mode = tmp_prof
123 | table.act_mode_idx = -1
124 | if tmp_prof == "TIME":
125 | check_day_table()
126 | kv = time_mode()
127 | elif tmp_prof == "TEMP":
128 | kv = temp_mode()
129 |
130 | return [table.selected_mode, table.act_mode_idx, kv]
131 |
132 |
133 | def init(dt, tt):
134 | """
135 | Init day and temp table
136 | :param dt: list, daytable
137 | :param tt: list, daytable
138 | :return: nothing
139 | """
140 | global table
141 | table.start(dt, tt)
142 |
--------------------------------------------------------------------------------
/obsolete/lib/weather.py:
--------------------------------------------------------------------------------
1 | import urllib
2 | import urllib2
3 | import logmsg
4 | import traceback
5 | from math import exp
6 | import json
7 |
8 |
9 | def weather_for_woeid(woeid, owm_id, owm_api_key):
10 | """
11 | Returns weather from yahoo weather from given WOEID
12 | :param owm_id:
13 | :param owm_api_key:
14 | :param woeid: integer, yahoo weather ID
15 | :return: dictionary, {"current_temp": temp, "city": city, "humidity": humidity}
16 | """
17 | city = "Error city"
18 | temp = None
19 | humidity = None
20 |
21 | if woeid is None or owm_id is None:
22 | logmsg.update("Wrong WOEID! Please set WOEID in config.py.", 'E')
23 | elif owm_api_key is None:
24 | logmsg.update("OWM API key not set!", 'E')
25 | else:
26 | # please change u='c' to u='f' for fahrenheit below
27 | base_url = "https://query.yahooapis.com/v1/public/yql?"
28 | yql_query = "select * from weather.forecast where woeid=" + str(woeid) + " and u='c'"
29 | yql_url = base_url + urllib.urlencode({'q': yql_query}) + "&format=json"
30 |
31 | try:
32 | result = urllib2.urlopen(yql_url).read()
33 | data = json.loads(result)
34 | except Exception, error:
35 | logmsg.update("Yahoo communication error: " + str(error), 'E')
36 | logmsg.update("Traceback: " + str(traceback.format_exc()), 'E')
37 | else:
38 | if data is not None:
39 | try:
40 | city = data["query"]["results"]["channel"]["location"]["city"]
41 | temp = int(data["query"]["results"]["channel"]["item"]["condition"]["temp"])
42 | humidity = int(data["query"]["results"]["channel"]["atmosphere"]["humidity"])
43 | except Exception:
44 | pass
45 | else:
46 | # and check if yahoo is correct
47 | url = "http://api.openweathermap.org/data/2.5/weather?id=" + str(owm_id) + "&appid=" + \
48 | owm_api_key + "&units=metric"
49 | try:
50 | result = json.load(urllib2.urlopen(url))
51 | except Exception, error:
52 | logmsg.update("OWM communication error: " + str(error), 'E')
53 | logmsg.update("Traceback: " + str(traceback.format_exc()), 'E')
54 | else:
55 | if "main" in result:
56 | owm_temp = round(result["main"]["temp"])
57 | yho_temp = round(temp)
58 | if abs(yho_temp - owm_temp) > 1.5:
59 | logmsg.update("Difference between Yahoo and OWM temperatures. Yahoo=" + str(yho_temp) +
60 | " OWM=" + str(owm_temp), 'I')
61 | # end check
62 | else:
63 | logmsg.update("Error during parsing result.", 'D')
64 | logmsg.update(
65 | "Current temperature in " + str(city) + " is " + str(temp) + ", humidity " + str(humidity) +
66 | "%", 'I')
67 |
68 | return {
69 | "current_temp": temp,
70 | "city": city,
71 | "humidity": humidity
72 | }
73 |
74 |
75 | def _scale(val, src, dst):
76 | """ Scale the given value from the scale of src to the scale of dst
77 | :param val: float, value to scale
78 | :param src: list, scale interval from
79 | :param dst: list, scale interval to
80 | :return: float
81 | """
82 | return ((val - src[0]) / (src[1] - src[0])) * (dst[1] - dst[0]) + dst[0]
83 |
84 |
85 | def interval_scale(temp, t, r, w, test):
86 | """
87 | :param temp: int, temperature
88 | :param t: list, temperature min, max range
89 | :param r: list, min, max for exp()
90 | :param w: list, target range, min max
91 | :param test: boolean, test for range violation
92 | :return: int, mapped value
93 | """
94 | if test:
95 | if temp < t[0]:
96 | temp = t[0]
97 | elif temp > t[1]:
98 | temp = t[1]
99 |
100 | a = _scale(temp, t, r)
101 | b = int(_scale(exp(a), (exp(r[0]), exp(r[1])), w))
102 |
103 | return b
104 |
105 |
--------------------------------------------------------------------------------
/obsolete/lib/autoupdate.py:
--------------------------------------------------------------------------------
1 | import urllib2
2 | import traceback
3 | import httplib
4 | import logmsg
5 | import os
6 | import hashlib
7 | import zipfile
8 |
9 |
10 | def get_hash(filename):
11 | checksum = hashlib.md5()
12 | if os.path.isfile(filename):
13 | f = file(filename, "rb")
14 | while True:
15 | part = f.read(1024)
16 | if not part:
17 | break
18 | checksum.update(part)
19 | f.close()
20 | return checksum
21 |
22 |
23 | def download_file(get_file, put_file):
24 | err_str = ""
25 | try:
26 | request = urllib2.urlopen(get_file)
27 | response = request.read()
28 | except urllib2.HTTPError, e:
29 | err_str += "HTTPError = " + str(e.reason)
30 | except urllib2.URLError, e:
31 | err_str += "URLError = " + str(e.reason)
32 | except httplib.HTTPException:
33 | err_str += "HTTPException"
34 | except Exception, e:
35 | err_str += "Exception = " + str(traceback.format_exc()) + ". Error: " + str(e)
36 | else:
37 | tmp_dir = os.path.dirname(put_file)
38 | if not os.path.exists(tmp_dir):
39 | os.mkdir(tmp_dir)
40 | try:
41 | f = file(put_file, "wb")
42 | except Exception, e:
43 | err_str = "Problem during saving new version. File: " + put_file + ". Error: " + str(
44 | e) + " Traceback: " + str(traceback.format_exc())
45 | else:
46 | f.write(response)
47 | f.close()
48 | err_str = ""
49 | request.close()
50 | finally:
51 | if not err_str == "":
52 | logmsg.update(err_str)
53 | return False
54 | return True
55 |
56 |
57 | def check_update(version):
58 | github = "https://github.com/autopower/thermeq3/raw/master/install/current/"
59 | home_dir = "/root/thermeq3"
60 | err_str = "Unable to get latest version info - "
61 |
62 | try:
63 | request = urllib2.urlopen(github + "autoupdate.data")
64 | response = request.read().rstrip("\r\n")
65 | except urllib2.HTTPError, e:
66 | err_str += "HTTPError = " + str(e.reason)
67 | except urllib2.URLError, e:
68 | err_str += "URLError = " + str(e.reason)
69 | except httplib.HTTPException:
70 | err_str += "HTTPException"
71 | except Exception:
72 | err_str += "Exception = " + str(traceback.format_exc())
73 | else:
74 | err_str = ""
75 | t = response.split(":")
76 |
77 | new_hash = get_hash(home_dir + "-install/" + str(t[1])).hexdigest()
78 | if new_hash == "":
79 | logmsg.update("Can't find file " + str(t[1]), 'E')
80 | else:
81 | try:
82 | tmp_ver = int(t[0])
83 | except Exception:
84 | tmp_ver = 0
85 | logmsg.update("Available file: " + str(t[1]) + ", V" + str(tmp_ver) + " with hash " + str(t[3]), 'I')
86 | logmsg.update("Actual version: " + str(version) + ", hash: " + str(new_hash), 'I')
87 | if new_hash != t[3] and version < tmp_ver:
88 | logmsg.update("Downloading new version V" + str(tmp_ver))
89 | down_result = download_file(github + t[1], home_dir + "-install/" + t[1])
90 | if down_result:
91 | logmsg.update("V" + str(tmp_ver) + " downloaded. Hash is " + str(t[3]))
92 | return [2, t[1]]
93 | else:
94 | logmsg.update("Problem downloading new version. Result=" + str(down_result) + ", file=" + str(t[1]))
95 | else:
96 | return [1, ""]
97 |
98 | if not err_str == "":
99 | logmsg.update(err_str)
100 | return [0, ""]
101 |
102 |
103 | def do(version):
104 | """
105 | Perform update
106 | :param version: string
107 | :return: boolean, True if something updated
108 | """
109 | home_dir = "/root/thermeq3"
110 | chk, filename = check_update(version)
111 | result = False
112 | if chk == 2:
113 | # unzip files
114 | with zipfile.ZipFile(home_dir + "-install/" + filename, "r") as z:
115 | try:
116 | z.extractall(home_dir + "/")
117 | except Exception:
118 | logmsg.update("Error during archive extraction", 'E')
119 | else:
120 | logmsg.update("Archive successfully extracted.", 'I')
121 | result = True
122 | elif chk == 1:
123 | logmsg.update("Update is not necessary.")
124 | return result
125 |
--------------------------------------------------------------------------------
/yun-sketch/thermeq3_V200/thermeq3_V200.ino:
--------------------------------------------------------------------------------
1 | // #define DEBUG_PRG
2 |
3 | #include
4 |
5 | #define RELAY_PIN 10
6 | #define STATUS_LED 9
7 | #define ERROR_LED 8
8 | #define LOOP_LED 13
9 | #define BLINK_INTERVAL 150
10 | #define WAIT_UPDATE_SYNC 10000
11 |
12 | #define IWANNABESAFE
13 |
14 | // define this if you wanna use some optocoupler for relay or reverse logic
15 | // #define REVERSE_LOGIC
16 | #ifdef REVERSE_LOGIC
17 | #define LOGIC_1 LOW
18 | #define LOGIC_0 HIGH
19 | #else
20 | #define LOGIC_1 HIGH
21 | #define LOGIC_0 LOW
22 | #endif
23 |
24 | Process p;
25 | char bridgeBuffer[16];
26 | boolean sysStatus = false;
27 | unsigned long waitUntil = 0;
28 | unsigned long interval = 10*1000; // interval in seconds, change 10 to anything you want
29 | unsigned long app_interval = 10*60000; // interval in minutes, change 10 to anything you want
30 | unsigned long waitForApp = 0;
31 |
32 | void alloff() {
33 | digitalWrite(LOOP_LED, LOW);
34 | digitalWrite(STATUS_LED, LOW);
35 | digitalWrite(ERROR_LED, LOW);
36 | }
37 |
38 | void allon() {
39 | digitalWrite(LOOP_LED, HIGH);
40 | digitalWrite(STATUS_LED, HIGH);
41 | digitalWrite(ERROR_LED, HIGH);
42 | }
43 |
44 | void blinkLED() {
45 | for (byte i = 0; i < 4; i++) {
46 | allon();
47 | delay(BLINK_INTERVAL);
48 | alloff();
49 | delay(BLINK_INTERVAL);
50 | }
51 | }
52 |
53 | void turnIt(boolean onoff) {
54 | showError(false);
55 | if (sysStatus == onoff) return;
56 |
57 | if (onoff) {
58 | digitalWrite(RELAY_PIN, LOGIC_1);
59 | digitalWrite(STATUS_LED, HIGH);
60 | } else {
61 | digitalWrite(RELAY_PIN, LOGIC_0);
62 | digitalWrite(STATUS_LED, LOW);
63 | }
64 | sysStatus = onoff;
65 | Bridge.put("msg", "");
66 | }
67 |
68 | void fatalError() {
69 | turnIt(false);
70 | alloff();
71 | while (true) {
72 | digitalWrite(LOOP_LED, HIGH);
73 | delay(BLINK_INTERVAL);
74 | digitalWrite(LOOP_LED, LOW);
75 | digitalWrite(STATUS_LED, HIGH);
76 | delay(BLINK_INTERVAL);
77 | digitalWrite(STATUS_LED, LOW);
78 | digitalWrite(ERROR_LED, HIGH);
79 | delay(BLINK_INTERVAL);
80 | digitalWrite(ERROR_LED, LOW);
81 | }
82 | }
83 |
84 | void showDead() {
85 | turnIt(false);
86 | alloff();
87 | while (true) {
88 | for(int j = 0 ; j <= 255; j +=5) {
89 | analogWrite(STATUS_LED, j);
90 | delay(30);
91 | }
92 | for(int j = 255 ; j >= 0; j -=10) {
93 | analogWrite(STATUS_LED, j);
94 | delay(30);
95 | }
96 | digitalWrite(STATUS_LED, LOW);
97 | delay(BLINK_INTERVAL * 5);
98 | }
99 | }
100 |
101 | void showError(boolean onoff) {
102 | if (onoff) digitalWrite(ERROR_LED, HIGH);
103 | else digitalWrite(ERROR_LED, LOW);
104 | Bridge.put("msg", "");
105 | }
106 |
107 | void runApp() {
108 | turnIt(false);
109 | // you can use p.begin("/root/nsm.py") without .addParameter
110 | p.begin("python");
111 | p.addParameter("/root/thermeq3/nsm.py");
112 | p.runAsynchronously();
113 | }
114 |
115 | void setup() {
116 | #ifdef DEBUG_PRG
117 | Serial.begin(9600);
118 | while (!Serial);
119 | #endif
120 |
121 | pinMode(RELAY_PIN, OUTPUT);
122 | pinMode(ERROR_LED, OUTPUT);
123 | pinMode(STATUS_LED, OUTPUT);
124 | pinMode(LOOP_LED, OUTPUT);
125 |
126 | blinkLED();
127 | allon();
128 | Bridge.begin();
129 | blinkLED();
130 |
131 | runApp();
132 |
133 | #ifdef DEBUG_PRG
134 | Serial.println("GO!");
135 | Serial.println(interval);
136 | Serial.println(app_interval);
137 | #endif
138 | }
139 |
140 | void loop() {
141 | unsigned long mls = millis();
142 |
143 | if (mls - waitUntil >= interval) {
144 | digitalWrite(LOOP_LED, HIGH);
145 | Bridge.get("msg", bridgeBuffer, 16);
146 | char c = bridgeBuffer[0];
147 |
148 | switch (c) {
149 | case 'H':
150 | turnIt(true);
151 | break;
152 | case 'S':
153 | turnIt(false);
154 | break;
155 | case 'E':
156 | #ifdef IWANNABESAFE
157 | turnIt(false);
158 | #endif
159 | showError(true);
160 | break;
161 | case 'A':
162 | alloff();
163 | break;
164 | case 'Q':
165 | fatalError();
166 | break;
167 | case 'D':
168 | turnIt(false);
169 | showDead();
170 | break;
171 | case 'R':
172 | #ifdef IWANNABESAFE
173 | turnIt(false);
174 | #endif
175 | digitalWrite(ERROR_LED, LOW);
176 | digitalWrite(STATUS_LED, LOW);
177 | digitalWrite(ERROR_LED, HIGH);
178 | digitalWrite(STATUS_LED, HIGH);
179 | p.close();
180 | delay(WAIT_UPDATE_SYNC);
181 | runApp();
182 | digitalWrite(ERROR_LED, LOW);
183 | digitalWrite(STATUS_LED, LOW);
184 | break;
185 | }
186 | waitUntil = waitUntil + interval;
187 | digitalWrite(LOOP_LED, LOW);
188 | }
189 |
190 | if (mls - waitForApp >= app_interval) {
191 | #ifdef DEBUG_PRG
192 | Serial.println(mls);
193 | Serial.println(p.running());
194 | #endif
195 | digitalWrite(LOOP_LED, HIGH);
196 | if (p.running() == false) {
197 | p.close();
198 | runApp();
199 | }
200 | waitForApp = waitForApp + app_interval;
201 | digitalWrite(LOOP_LED, LOW);
202 | }
203 |
204 | }
205 |
--------------------------------------------------------------------------------
/yun-sketch/thermeq3/thermeq3.ino:
--------------------------------------------------------------------------------
1 | // #define DEBUG_PRG
2 |
3 | #include
4 |
5 | #define RELAY_PIN 10
6 | // #define RELAY_POWER 8
7 | #define STATUS_LED 9
8 | #define ERROR_LED 8
9 | #define LOOP_LED 13
10 | #define BLINK_INTERVAL 150
11 | #define WAIT_UPDATE_SYNC 10000
12 |
13 | #define IWANNABESAFE
14 |
15 | Process p;
16 | char bridgeBuffer[16];
17 | boolean sysStatus = false;
18 | unsigned long waitUntil = 0;
19 | unsigned long interval = 10*1000; // interval in seconds, change 10 to anything you want
20 | unsigned long app_interval = 5*60000; // interval in minutes, change 5 to anything you want
21 | unsigned long waitForApp = 0;
22 |
23 | void blinkLED() {
24 | for (byte i = 0; i < 4; i++) {
25 | digitalWrite(LOOP_LED, HIGH);
26 | digitalWrite(STATUS_LED, HIGH);
27 | digitalWrite(ERROR_LED, HIGH);
28 | delay(BLINK_INTERVAL);
29 | digitalWrite(LOOP_LED, LOW);
30 | digitalWrite(STATUS_LED, LOW);
31 | digitalWrite(ERROR_LED, LOW);
32 | delay(BLINK_INTERVAL);
33 | }
34 | }
35 |
36 | void turnIt(boolean onoff) {
37 | showError(false);
38 | if (sysStatus == onoff) return;
39 |
40 | if (onoff) {
41 | #ifdef RELAY_POWER
42 | digitalWrite(RELAY_POWER, HIGH);
43 | delay(500);
44 | #endif
45 | digitalWrite(RELAY_PIN, HIGH);
46 | digitalWrite(STATUS_LED, HIGH);
47 | } else {
48 | digitalWrite(RELAY_PIN, LOW);
49 | #ifdef RELAY_POWER
50 | delay(500);
51 | digitalWrite(RELAY_POWER, LOW);
52 | #endif
53 | digitalWrite(STATUS_LED, LOW);
54 | }
55 | sysStatus = onoff;
56 | Bridge.put("msg", "");
57 | }
58 |
59 | void fatalError() {
60 | turnIt(false);
61 | digitalWrite(LOOP_LED, LOW);
62 | digitalWrite(STATUS_LED, LOW);
63 | digitalWrite(ERROR_LED, LOW);
64 | while (true) {
65 | digitalWrite(LOOP_LED, HIGH);
66 | delay(BLINK_INTERVAL);
67 | digitalWrite(LOOP_LED, LOW);
68 | digitalWrite(STATUS_LED, HIGH);
69 | delay(BLINK_INTERVAL);
70 | digitalWrite(STATUS_LED, LOW);
71 | digitalWrite(ERROR_LED, HIGH);
72 | delay(BLINK_INTERVAL);
73 | digitalWrite(ERROR_LED, LOW);
74 | }
75 | }
76 |
77 | void showDead() {
78 | turnIt(false);
79 | digitalWrite(LOOP_LED, LOW);
80 | digitalWrite(STATUS_LED, LOW);
81 | digitalWrite(ERROR_LED, LOW);
82 | while (true) {
83 | for(int j = 0 ; j <= 255; j +=5) {
84 | analogWrite(STATUS_LED, j);
85 | delay(30);
86 | }
87 |
88 | for(int j = 255 ; j >= 0; j -=10) {
89 | analogWrite(STATUS_LED, j);
90 | delay(30);
91 | }
92 | digitalWrite(STATUS_LED, LOW);
93 | delay(BLINK_INTERVAL * 5);
94 | }
95 | }
96 |
97 | void showError(boolean onoff) {
98 | if (onoff) digitalWrite(ERROR_LED, HIGH);
99 | else digitalWrite(ERROR_LED, LOW);
100 | Bridge.put("msg", "");
101 | }
102 |
103 | void runApp() {
104 | turnIt(false);
105 | // start python app
106 | p.begin("python");
107 | p.addParameter("/root/thermeq3/nsm.py");
108 | p.runAsynchronously();
109 | }
110 |
111 | void signalReadNotOK() {
112 | turnIt(false);
113 | for (byte i = 0; i < 4; i++) {
114 | digitalWrite(ERROR_LED, HIGH);
115 | delay(BLINK_INTERVAL);
116 | digitalWrite(ERROR_LED, LOW);
117 | delay(BLINK_INTERVAL);
118 | }
119 | }
120 |
121 | void setup() {
122 | #ifdef DEBUG_PRG
123 | Serial.begin(9600);
124 | while (!Serial);
125 | #endif
126 |
127 | pinMode(RELAY_PIN, OUTPUT);
128 | #ifdef RELAY_POWER
129 | pinMode(RELAY_POWER, OUTPUT);
130 | #endif
131 | pinMode(ERROR_LED, OUTPUT);
132 | pinMode(STATUS_LED, OUTPUT);
133 | pinMode(LOOP_LED, OUTPUT);
134 |
135 | blinkLED();
136 | digitalWrite(STATUS_LED, HIGH);
137 | digitalWrite(ERROR_LED, HIGH);
138 | digitalWrite(LOOP_LED, HIGH);
139 | Bridge.begin();
140 | blinkLED();
141 |
142 | runApp();
143 |
144 | #ifdef DEBUG_PRG
145 | Serial.println("GO!");
146 | Serial.println(interval);
147 | Serial.println(app_interval);
148 | #endif
149 | }
150 |
151 | void loop() {
152 | unsigned long mls = millis();
153 |
154 | if (mls - waitUntil >= interval) {
155 | digitalWrite(LOOP_LED, HIGH);
156 | Bridge.get("msg", bridgeBuffer, 16);
157 | char c = bridgeBuffer[0];
158 |
159 | switch (c) {
160 | case 'H':
161 | turnIt(true);
162 | break;
163 | case 'S':
164 | turnIt(false);
165 | break;
166 | case 'E':
167 | // in case that cube is not available, e.g. timeout
168 | #ifdef IWANNABESAFE
169 | turnIt(false);
170 | #endif
171 | showError(true);
172 | break;
173 | case 'C':
174 | showError(false);
175 | break;
176 | case 'Q':
177 | fatalError();
178 | break;
179 | case 'D':
180 | turnIt(false);
181 | showDead();
182 | break;
183 | case 'M':
184 | // in case that read from max cube malformed
185 | signalReadNotOK();
186 | break;
187 | case 'R':
188 | #ifdef IWANNABESAFE
189 | turnIt(false);
190 | #endif
191 | digitalWrite(ERROR_LED, HIGH);
192 | digitalWrite(STATUS_LED, HIGH);
193 | p.close();
194 | delay(WAIT_UPDATE_SYNC);
195 | runApp();
196 | break;
197 | }
198 | waitUntil = waitUntil + interval;
199 | digitalWrite(LOOP_LED, LOW);
200 | }
201 |
202 | if (mls - waitForApp >= app_interval) {
203 | #ifdef DEBUG_PRG
204 | Serial.println(mls);
205 | Serial.println(p.running());
206 | #endif
207 | digitalWrite(LOOP_LED, HIGH);
208 | if (p.running() == false) {
209 | p.close();
210 | runApp();
211 | }
212 | waitForApp = waitForApp + app_interval;
213 | digitalWrite(LOOP_LED, LOW);
214 | }
215 |
216 | }
217 |
--------------------------------------------------------------------------------
/obsolete/lib/mailer.py:
--------------------------------------------------------------------------------
1 | import smtplib
2 | import logmsg
3 | import os
4 | import traceback
5 | from email.mime.multipart import MIMEMultipart
6 | from email.mime.text import MIMEText
7 | from email.mime.base import MIMEBase
8 | from email.encoders import encode_base64
9 | import thermeq3
10 |
11 | subject_body = {"battery": ["Battery status for device %(b0)s. Warning from thermeq3 device",
12 | """
Device %(a0)s battery status warning.
13 |
Hello, I'm your thermostat and I have a warning for you.
14 | Please take a care of device %(a0)s in room %(a1)s.
15 | This device have low batteries, please replace batteries.
16 |
You can mute this warning for %(a3)s mins."""],
17 | "error": ["Error report for device %(a0)s. Warning from thermeq3 device",
18 | """
Device %(a0)s radio error.
19 |
Hello, I'm your thermostat and I have a warning for you.
20 | Please take a care of device %(a0)s in room %(a1)s.
21 | This device reports error.
22 |
You can mute this warning for %(a3)s mins."""],
23 | "openmax": ["Can't connect to MAX! Cube! Warning from thermeq3 device", ""],
24 | "upgrade": ["thermeq3 device is going to be upgraded", ""],
25 | "window": ["Open window in room %(b0)s. Warning from thermeq3 device",
26 | """
Device %(a0)s warning.
27 |
Hello, I'm your thermostat and I have a warning for you.
28 | Please take a care of window %(a0)s in room %(a1)s.
29 | Window in this room is now opened more than %(a2)s.
30 | Threshold for warning is %(a3)d mins.
31 |