aboutsummaryrefslogtreecommitdiff
path: root/py_relay.py
blob: 0c98d7fba5deacc2873eb513a251c36c579cb44d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
Module managing temperature in an enclosed space via heater,
turning relay on and off.
Gets temperature from one wire sensor.
Attempts to keep temperature between given min and max.
Writes its own log as well as temperature data with timestamps to CSV file.
"""
import getpass

import pigpio
from math import isnan
import logging
import time
from csv import writer

__author__ = "Franek Ɓazarewicz-Muradyan"
__licence__ = "GPL"
__version__ = "0.0.1"
__status__ = "Development"

# One wire temperature sensor settings
W1_SENSOR_ID = '28-0517c1b121ff'
W1_SENSOR_F = f'/sys/devices/w1_bus_master1/{W1_SENSOR_ID}/w1_slave'
# Heater settings
HEATER_PIN = 5
# Other settings
TIMEFORMAT = '%Y-%M-%d %H:%M:%S'
TEMPERATURE_MIN = 20
TEMPERATURE_MAX = 24
# TEMPERATURE_MIN = 28
# TEMPERATURE_MAX = 32
USERNAME = getpass.getuser()
LOGNAME = f'/var/log/{USERNAME}/shroombox.log'
DATA_FILE = f'/var/log/{USERNAME}/shroombox.csv'

pio = pigpio.pi()

logging.basicConfig(
    filename=LOGNAME,
    encoding='utf-8',
    filemode='a',
    format='%(asctime)s,%(msecs)d %(name)s%(levelname)s %(message)s', datefmt='%H:%M:%S',
    level=logging.DEBUG,
)

logging.info("Starting shroombox")

logger = logging.getLogger()


def read_temp_alt(retry=0) -> float:
    """
    Function reading temperature.
    :param retry: int
    :return: float
    """
    # If sensor is physically disconected, opening file will fail
    temperature = float('NaN')
    if retry > 3:
        return temperature
    try:
        with open(W1_SENSOR_F, 'r') as sensor:
            ok = sensor.readline()[-4:].strip('\n')
            if ok == 'YES':
                try:
                    temperature = round(int(sensor.readline().split('=')[1])/1000, 1)
                except:
                    return temperature
            else:
                retry+=1
                read_temp_alt(retry=retry)
    except:
        return temperature
    return temperature


def heater_on(temp, on=False) -> bool:
    """
    Function turning heater on.
    :param temp: int
    :param on: bool
    :return: bool
    """
    status = pio.read(HEATER_PIN)
    timestamp = time.strftime(TIMEFORMAT)
    # turning it off
    if not on:
        if status:
            retval = 0
        else:
            try:
                pio.write(HEATER_PIN, 1)
                message = f"Turning off, temp: {temp}, {timestamp}"
                logger.info(message)
                retval = 0
            except Exception as exc:
                logger.warning(exc)
                retval = 1
    # turning it on
    else:
        if not status:
            retval = 0
        else:
            try:
                pio.write(HEATER_PIN, 0)
                message = f"Turning on, temp: {temp}, {timestamp}"
                logger.info(message)
                retval = 0
            except Exception as exc:
                logger.warning(exc)
                retval = 1
    return retval


def callback():
    temp = read_temp_alt()
    #  TODO: Add check ntp is running, else we may go back to the '70-ties
    timestamp = time.strftime(TIMEFORMAT)
    try:
        with open(DATA_FILE, 'a') as _file:
            wrtr = writer(_file)
            wrtr.writerow((timestamp, temp))
    except OSError as exc:
        print(f"Error writing data to file: {exc}")
    print(temp) # TODO: Remove this line when done with testing.
    if temp <= TEMPERATURE_MIN:
        if temp < TEMPERATURE_MIN - 5:
            print(f"Temperature below minimum: {temp}. Heater not powerful enough?")
            logger.warning(f"Heater doesn't work, battery empty?")
        state = heater_on(temp, on=True)
        if state != 0:
            logger.warning(f"heater_on() method returned {state}, {timestamp}")
    elif temp >= TEMPERATURE_MAX:
        state = heater_on(temp, on=False)
        if state != 0:
            logger.warning(f"heater_on() method returned {state} {timestamp}")
    # Turn off in case can't get temperature reading:
    elif isnan(temp):
        state = heater_on(temp, on=False)
        if state != 0:
            logger.warning(f"heater_on() method returned {state} {timestamp}")
        logging.warning(f"Cannot read temperature, check your connections! {timestamp}")


if __name__ == '__main__':
    while True:
        callback()
        time.sleep(30)