diff --git a/bot/conf/ext_greenhouse_lib.py b/bot/conf/ext_greenhouse_lib.py index be9af5e..c4d2934 100644 --- a/bot/conf/ext_greenhouse_lib.py +++ b/bot/conf/ext_greenhouse_lib.py @@ -22,13 +22,25 @@ cmd_live = '{0}live'.format(cmd_prefix) cmd_kill = '{0}kill'.format(cmd_prefix) -msg_help = 'Usage and possible commands in special mode:{0}{1} - this info{0}{2} - restart the whole RSBPi{0}{3} - ' \ - 'force update{0}{4} - force archiving and cleaning of log files{0}{5} - stop this bot mode ' \ - '{0}{6}- switch all on{0}{7}- switch all off{0}{8}- switch group 1 on{0}{9}- switch group 1 ' \ - 'off{0}{10}- switch group 2 on{0}{11}- switch group 2 off{0}{12}- switch group 3 on{0}{13}- switch ' \ - 'group 3 off{0}{14} - Live stream'.format( - newline, cmd_help, cmd_restart, cmd_update, cmd_logrotate, cmd_kill, cmd_all_on, cmd_all_off, cmd_group1_on, - cmd_group1_off, cmd_group2_on, cmd_group2_off, cmd_group3_on, cmd_group3_off, cmd_live) +msg_help = 'Usage and possible commands in special mode:{0}' \ + '{1} - this info{0}' \ + '{2} - restart the whole RSBPi{0}' \ + '{3} - force update{0}' \ + '{4} - force archiving and cleaning of log files{0}' \ + '{5} - stop this mode{0}' \ + '{6} - switch all on{0}' \ + '{7} - switch all off{0}' \ + '{8} - switch group 1 on{0}' \ + '{9} - switch group 1 off{0}' \ + '{10} - switch group 2 on{0}' \ + '{11} - switch group 2 off{0}' \ + '{12} - switch group 3 on{0}' \ + '{13} - switch group 3 off{0}' \ + '{14} - Live stream'\ + .format(newline, + cmd_help, cmd_restart, cmd_update, cmd_logrotate, cmd_kill, + cmd_all_on, cmd_all_off, cmd_group1_on, cmd_group1_off, cmd_group2_on, + cmd_group2_off, cmd_group3_on, cmd_group3_off, cmd_live) msg_unknown = 'Unknown in this mode...!\nPlease use /help for more information.' msg_update = 'Update forced manually, info is available in separate log file.' diff --git a/bot/conf/greenhouse_config.py b/bot/conf/greenhouse_config.py index 4391d59..8e409ac 100644 --- a/bot/conf/greenhouse_config.py +++ b/bot/conf/greenhouse_config.py @@ -1,16 +1,10 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -# configs, constants and methods +# configs, command strings and constants # author: Thomas Kaulke, kaulketh@gmail.com from __future__ import absolute_import -import time -import RPi.GPIO as GPIO import conf.access as access -import logger.logger as log - -"""logging is configured in logger package in logger_config.ini""" -logging = log.get_logger('config') # language selection """ for English import greenhouse_lib_english """ @@ -32,18 +26,7 @@ [lib.stop_bot, lib.live_stream, lib.reload] ] kb2 = [[lib.cancel, lib.stop_bot]] - - -# to use Raspberry Pi board pin numbers -def set_pins(): - GPIO.setmode(GPIO.BOARD) - logging.info('Set GPIO mode: GPIO.BOARD') - # to use GPIO instead board pin numbers, then please adapt pin definition - # GPIO.setmode(GPIO.BCM) - # comment if warnings required - GPIO.setwarnings(False) - return GPIO - +kb3 = [[lib.emergency_stop]] # 7-segment display settings clk_pin = 32 @@ -88,38 +71,5 @@ def set_pins(): run_gpio_check = 'sudo python /home/pi/scripts/TelegramBot/gpio_check.py ' -# switch functions -def switch_on(pin): - logging.info('switch on: ' + str(pin)) - GPIO.setup(pin, GPIO.OUT) - GPIO.output(pin, GPIO.LOW) - # os.system(run_gpio_check + str(pin)) - return - - -def switch_off(pin): - logging.info('switch off: ' + str(pin)) - GPIO.setup(pin, GPIO.OUT) - GPIO.output(pin, GPIO.HIGH) - # os.system(run_gpio_check + str(pin)) - GPIO.cleanup(pin) - return - - -# date time strings -def get_timestamp(): - return time.strftime('[%d.%m.%Y %H:%M:%S] ') - - -def get_timestamp_line(): - return time.strftime('`[%d.%m.%Y %H:%M:%S]\n---------------------\n`') - - -# gets the state of pin, if 0 is switched on -def get_pin_state(pin): - GPIO.setup(pin, GPIO.OUT) - return GPIO.input(pin) - - if __name__ == '__main__': pass diff --git a/bot/conf/greenhouse_lib_english.py b/bot/conf/greenhouse_lib_english.py index a5cc976..a44736e 100644 --- a/bot/conf/greenhouse_lib_english.py +++ b/bot/conf/greenhouse_lib_english.py @@ -23,6 +23,7 @@ all_channels = 'All' stop_bot = 'End' live_stream = 'Take a look!' +emergency_stop = 'EMERGENCY STOP' reload = 'Reload' group1 = ('Channel 1 to 3', 'Channel 1', 'Channel 2', 'Channel 3') group2 = ('Channel 6 to 8', 'Channel 6', 'Channel 7', 'Channel 8') @@ -37,7 +38,7 @@ msg_live = '[Click here for the live stream]({})' msg_temperature = '`{}Current values\n{}, {}\n{}`' msg_welcome = '`Hello {}!`' -msg_stop = '` STANDBY `' +msg_stop = '` S T A N D B Y `' msg_duration = '`Specify switching time for \'{}\' in ' + time_units_name[time_units_index] + ':`' water_on = '`\'{}\' is switched on for {}' + time_units_sign[time_units_index] + '.`' water_on_group = '`{} are switched on for {}' + time_units_sign[time_units_index] + '.`' diff --git a/bot/conf/greenhouse_lib_german.py b/bot/conf/greenhouse_lib_german.py index b53f739..8d2b275 100644 --- a/bot/conf/greenhouse_lib_german.py +++ b/bot/conf/greenhouse_lib_german.py @@ -24,6 +24,7 @@ stop_bot = 'Beenden' live_stream = 'Schau mal!' reload = 'Aktualisieren' +emergency_stop = 'NOT - STOP' group1 = ('Kanal 1 bis 3', 'Kanal 1', 'Kanal 2', 'Kanal 3') group2 = ('Kanal 6 bis 8', 'Kanal 6', 'Kanal 7', 'Kanal 8') group3 = ('Kanal 4 und 5', 'Kanal 4', 'Kanal 5') @@ -36,7 +37,7 @@ msg_live = '[Hier gehts zum Live Stream]({})' msg_temperature = '`{}Aktuelle Werte\n{}, {}\n{}`' msg_welcome = '`Hallo {}!`' -msg_stop = '` STANDBY `' +msg_stop = '` S T A N D B Y `' msg_duration = '`Schaltzeit für \'{}\' in ' + time_units_name[time_units_index] + ' angeben:`' water_on = '`\'{}\' wird jetzt für {}' + time_units_sign[time_units_index] + ' eingeschaltet.`' water_on_group = '`{} werden jetzt für {}' + time_units_sign[time_units_index] + ' eingeschalten.`' @@ -46,8 +47,9 @@ water_off_all = '`Alles wurde nach {}' + time_units_sign[time_units_index] + ' wieder abgeschalten.`\n\n' msg_choice = '`Bitte auswählen:`' msg_new_choice = '`Neue Auswahl oder Beenden?`' -msg_panic = '`PANIK-MODUS!`' +msg_panic = '*PANIK-MODUS*' private_warning = '`Hallo {}, dies ist ein privater Bot!\nDeine ChatID: {} ist geblockt worden.`' + if __name__ == '__main__': pass diff --git a/bot/conf/keyboard_lib.py b/bot/conf/keyboard_lib.py deleted file mode 100644 index b5007a1..0000000 --- a/bot/conf/keyboard_lib.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# author: Thomas Kaulke, kaulketh@gmail.com - - -from telepot.namedtuple import InlineKeyboardMarkup, InlineKeyboardButton - - -kbd2 = [[InlineKeyboardButton(text='Google', url='www.google.de')], - [InlineKeyboardButton(text='R+', url='www.rammstein.de')] - ] - -keyboard2 = InlineKeyboardMarkup(inline_keyboard=[kbd2]) - diff --git a/bot/ext_greenhouse.py b/bot/ext_greenhouse.py index bed5353..b52a510 100644 --- a/bot/ext_greenhouse.py +++ b/bot/ext_greenhouse.py @@ -9,6 +9,7 @@ from __future__ import absolute_import import conf.greenhouse_config as conf import conf.ext_greenhouse_lib as lib +import utils.utils as utils import peripherals.four_digit.display as display import sys import time @@ -16,7 +17,7 @@ import os import logger.logger as log -logging = log.get_logger('extended bot') +logging = log.get_logger() pins_state = False @@ -46,14 +47,14 @@ # water a group of targets def _water_on_group(group): for member in group: - conf.switch_on(member) + utils.switch_on(member) return # water off for a group of targets def _water_off_group(group): for member in group: - conf.switch_off(member) + utils.switch_off(member) return @@ -78,7 +79,7 @@ def _send_msg(message, parse_mode): def _check_pins_state(): global pins_state for pin in group_all: - if not conf.get_pin_state(pin): + if not utils.get_pin_state(pin): display.show_on() pins_state = False break @@ -107,19 +108,19 @@ def _handle(msg): elif command == lib.cmd_logrotate: _send_msg(_read_cmd(lib.logrotate_bot), no_parse_mode) elif command == lib.cmd_all_on: - _send_msg(conf.get_timestamp() + ' all on', no_parse_mode) + _send_msg(utils.get_timestamp() + ' all on', no_parse_mode) _water_on_group(group_all) elif command == lib.cmd_all_off: _send_msg('all off.', no_parse_mode) _water_off_group(group_all) elif command == lib.cmd_group1_on: - _send_msg(conf.get_timestamp() + 'group 1 on', no_parse_mode) + _send_msg(utils.get_timestamp() + 'group 1 on', no_parse_mode) _water_on_group(group_one) elif command == lib.cmd_group1_off: _send_msg('group 1 off', no_parse_mode) _water_off_group(group_one) elif command == lib.cmd_group2_on: - _send_msg(conf.get_timestamp() + 'group 2 on', no_parse_mode) + _send_msg(utils.get_timestamp() + 'group 2 on', no_parse_mode) _water_on_group(group_two) elif command == lib.cmd_group2_off: _send_msg('group 2 off', no_parse_mode) @@ -154,7 +155,7 @@ def init_and_start(): # logging.info('{0} is PID of running default bot, used to kill.'.format(str(pid1))) _read_cmd('kill -9 {0}'.format(str(pid1))) - conf.set_pins() + utils.set_pins() bot = telepot.Bot(apiToken) bot.message_loop(_handle) logging.info('I am listening...') diff --git a/bot/greenhouse.py b/bot/greenhouse.py index d19e110..da98875 100644 --- a/bot/greenhouse.py +++ b/bot/greenhouse.py @@ -1,7 +1,7 @@ #!/usr/bin/python # -*- coding: utf-8 -*- # main script for greenhouse bot -# using telegram as Python framework for Telegram Bot API +# using telegram.ext as Python framework for Telegram Bot API # https://core.telegram.org/api#bot-api # original: author: Stefan Weigert http://www.stefan-weigert.de/php_loader/raspi.php # adapted: author: Thomas Kaulke, kaulketh@gmail.com @@ -9,17 +9,19 @@ from __future__ import absolute_import import os import time +import utils.utils as utils import conf.greenhouse_config as conf import peripherals.dht.dht as dht import peripherals.temperature as core -import peripherals.timeout as timeout +import utils.stop_and_restart as stop_and_restart import peripherals.four_digit.display as display import logger.logger as log from telegram import ReplyKeyboardMarkup, ReplyKeyboardRemove, ParseMode from telegram.ext import Updater, CommandHandler, RegexHandler, ConversationHandler +from telegram.ext.dispatcher import run_async -logging = log.get_logger('greenhouse bot') +logging = log.get_logger() # used library lib = conf.lib @@ -31,7 +33,7 @@ group_three = conf.GROUP_03 # api and bot settings -SELECT, DURATION = range(2) +SELECTION, DURATION = range(2) # LIST_OF_ADMINS = ['mock to test'] list_of_admins = conf.admins token = conf.token @@ -41,24 +43,25 @@ jq = None timer_job = None + # keyboard config markup1 = ReplyKeyboardMarkup(conf.kb1, resize_keyboard=True, one_time_keyboard=False) markup2 = ReplyKeyboardMarkup(conf.kb2, resize_keyboard=True, one_time_keyboard=False) +markup3 = ReplyKeyboardMarkup(conf.kb3, resize_keyboard=True, one_time_keyboard=True) # Start info -def _init_bot_set_pins(): +def __init_bot_set_pins(): logging.info('Initialize bot, setup GPIO pins.') - conf.set_pins() + utils.set_pins() logging.info('Switch all off at start.') - for member in all_groups: - conf.switch_off(member) + __all_off() display.show_standby() return # start bot -def _start(bot, update): +def __start(bot, update): global user_id try: @@ -85,8 +88,8 @@ def _start(bot, update): else: display.show_run() logging.info('Bot started.') - _message_values(update) - _cam_on() + __message_values(update) + __cam_on() display.show_ready() update.message.reply_text('{0}{1}{2}'.format( lib.msg_welcome.format(update.message.from_user.first_name), lib.line_break, lib.msg_choice), @@ -96,16 +99,16 @@ def _start(bot, update): logging.info('Time unit is \'{0}\''.format(str(lib.time_units_name[lib.time_units_index]))) display.show_off() - _start_standby_timer(bot, update) - return SELECT + __start_standby_timer(bot, update) + return SELECTION # set the target, member of group or group -def _selection(bot, update): +def __selection(bot, update): global target target = update.message.text - _stop_standby_timer(bot, update) + __stop_standby_timer(bot, update) if target == str(lib.panic): update.message.reply_text(lib.msg_panic, @@ -116,30 +119,32 @@ def _selection(bot, update): elif target == str(lib.live_stream): logging.info('Live URL requested.') update.message.reply_text(lib.msg_live.format(str(conf.live)), parse_mode=ParseMode.MARKDOWN) - _start_standby_timer(bot, update) - return SELECT + __start_standby_timer(bot, update) + return SELECTION elif target == str(lib.reload): logging.info('Refresh values requested.') - _message_values(update) - _start_standby_timer(bot, update) - return SELECT + __message_values(update) + __start_standby_timer(bot, update) + return SELECTION else: update.message.reply_text(lib.msg_duration.format(target), parse_mode=ParseMode.MARKDOWN, reply_markup=markup2) logging.info('Selection: {0}'.format(str(target))) - _start_standby_timer(bot, update) + __start_standby_timer(bot, update) return DURATION # set water duration -def _duration(bot, update): +def __duration(bot, update): global water_time + global g_duration_update + g_duration_update = update water_time = update.message.text - _stop_standby_timer(bot, update) + __stop_standby_timer(bot, update) if water_time == str(lib.cancel): update.message.reply_text(lib.msg_new_choice, @@ -155,122 +160,154 @@ def _duration(bot, update): elif target == str(lib.group1[1]): """ starts separate thread""" display.show_switch_channel_duration(1, int(water_time)) - _water(update, group_one[0]) + + __water(bot, update, group_one[0]) elif target == str(lib.group1[2]): """ starts separate thread""" display.show_switch_channel_duration(2, int(water_time)) - _water(update, group_one[1]) + + __water(bot, update, group_one[1]) elif target == str(lib.group1[3]): """ starts separate thread""" display.show_switch_channel_duration(3, int(water_time)) - _water(update, group_one[2]) + + __water(bot, update, group_one[2]) elif target == str(lib.group2[1]): """ starts separate thread""" display.show_switch_channel_duration(6, int(water_time)) - _water(update, group_two[0]) + + __water(bot, update, group_two[0]) elif target == str(lib.group2[2]): """ starts separate thread""" display.show_switch_channel_duration(7, int(water_time)) - _water(update, group_two[1]) + + __water(bot, update, group_two[1]) elif target == str(lib.group2[3]): """ starts separate thread""" display.show_switch_channel_duration(8, int(water_time)) - _water(update, group_two[2]) + + __water(bot, update, group_two[2]) elif target == str(lib.group1[0]): """ starts separate thread""" display.show_switch_group_duration(1, int(water_time)) - _water_group(update, group_one) + + __water_group(bot, update, group_one) elif target == str(lib.group2[0]): """ starts separate thread""" display.show_switch_group_duration(2, int(water_time)) - _water_group(update, group_two) + + __water_group(bot, update, group_two) elif target == str(lib.group3[1]): """ starts separate thread""" display.show_switch_channel_duration(4, int(water_time)) - _water(update, group_three[0]) + + __water(bot, update, group_three[0]) elif target == str(lib.group3[2]): """ starts separate thread""" display.show_switch_channel_duration(5, int(water_time)) - _water(update, group_three[1]) + + __water(bot, update, group_three[1]) elif target == str(lib.group3[0]): """ starts separate thread""" display.show_switch_group_duration(3, int(water_time)) - _water_group(update, group_three) + + __water_group(bot, update, group_three) elif target == str(lib.all_channels): - _water_all(update) + __water_all(bot, update) else: update.message.reply_text(lib.msg_choice, reply_markup=markup1) - _start_standby_timer(bot, update) - return SELECT + __start_standby_timer(bot, update) + return SELECTION # watering targets -def _water_all(update): +def __all_off(): + logging.info('Switch all off.') + for channel in all_groups: + utils.switch_off(channel) + return + + +@run_async +def __water_all(bot, update): logging.info('Duration: {0}'.format(water_time)) + __stop_standby_timer(bot, update) update.message.reply_text(lib.water_on_all.format(target, water_time), - parse_mode=ParseMode.MARKDOWN, reply_markup=ReplyKeyboardRemove()) + parse_mode=ParseMode.MARKDOWN, reply_markup=markup3) + """ starts separate thread""" display.show_switch_group_duration(0, int(water_time)) + for channel in all_groups: - conf.switch_on(channel) - time.sleep((int(water_time) * int(lib.time_conversion))) - for channel in all_groups: - conf.switch_off(channel) + utils.switch_on(channel) + time.sleep(int(water_time) * int(lib.time_conversion)) + __all_off() + update.message.reply_text('{0}{1}{2}'.format( - _timestamp(), lib.water_off_all.format(water_time), lib.msg_new_choice), + __timestamp(), lib.water_off_all.format(water_time), lib.msg_new_choice), parse_mode=ParseMode.MARKDOWN, reply_markup=markup1) display.show_off() + __start_standby_timer(bot, update) return -def _water(update, channel): - logging.info('Duration: ' + water_time) - logging.info('Toggle ' + str(channel)) +@run_async +def __water(bot, update, channel): + logging.info('Duration: {0}'.format(water_time)) + logging.info('Toggle {0}'.format(str(channel))) + __stop_standby_timer(bot, update) update.message.reply_text(lib.water_on.format(target, water_time), - parse_mode=ParseMode.MARKDOWN, reply_markup=ReplyKeyboardRemove()) - conf.switch_on(channel) - time.sleep((int(water_time) * int(lib.time_conversion))) - conf.switch_off(channel) + parse_mode=ParseMode.MARKDOWN, reply_markup=markup3) + + utils.switch_on(channel) + time.sleep(int(water_time) * int(lib.time_conversion)) + utils.switch_off(channel) + update.message.reply_text('{0}{1}{2}'.format( - _timestamp(), lib.water_off.format(target, water_time), lib.msg_new_choice), + __timestamp(), lib.water_off.format(target, water_time), lib.msg_new_choice), parse_mode=ParseMode.MARKDOWN, reply_markup=markup1) display.show_off() + __start_standby_timer(bot, update) return -def _water_group(update, group): - logging.info('Duration: ' + water_time) - logging.info('Toggle ' + str(group)) +@run_async +def __water_group(bot, update, group): + logging.info('Duration: {0}'.format(water_time)) + logging.info('Toggle {0}'.format(str(group))) + __stop_standby_timer(bot, update) update.message.reply_text(lib.water_on_group.format(target, water_time), - parse_mode=ParseMode.MARKDOWN, reply_markup=ReplyKeyboardRemove()) + parse_mode=ParseMode.MARKDOWN, reply_markup=markup3) + for channel in group: - conf.switch_on(channel) + utils.switch_on(channel) time.sleep((int(water_time) * int(lib.time_conversion))) for channel in group: - conf.switch_off(channel) + utils.switch_off(channel) update.message.reply_text('{0}{1}{2}'.format( - _timestamp(), lib.water_off_group.format(target, water_time), lib.msg_new_choice), + __timestamp(), lib.water_off_group.format(target, water_time), lib.msg_new_choice), parse_mode=ParseMode.MARKDOWN, reply_markup=markup1) display.show_off() + __start_standby_timer(bot, update) return # humidity and temperature -def _message_values(update): - """to avoid refresh intervals shorter than 3 seconds""" +def __message_values(update): + # to avoid refresh intervals shorter than 3 seconds time.sleep(3) dht.get_values() if dht.temperature == 0: @@ -285,15 +322,18 @@ def _message_values(update): core_temp = (lib.core + lib.colon_space + core.get_temperature()) update.message.reply_text(lib.msg_temperature.format( - _start_time(), temp, hum, core_temp), parse_mode=ParseMode.MARKDOWN) + __start_time(), temp, hum, core_temp), parse_mode=ParseMode.MARKDOWN) return # stop bot -def _stop(bot, update): - _stop_standby_timer(bot, update) +def __stop(bot, update): + global enable_emergency_stop + enable_emergency_stop = False + __all_off() + __stop_standby_timer(bot, update) logging.info('Bot stopped.') - _cam_off() + __cam_off() display.show_stop() update.message.reply_text(lib.msg_stop, parse_mode=ParseMode.MARKDOWN, reply_markup=ReplyKeyboardRemove()) time.sleep(2) @@ -301,60 +341,79 @@ def _stop(bot, update): return ConversationHandler.END +# emergency stop +@run_async +def __emergency_stop_handler(bot, update, chat_data): + emergency = update.message.text + if not emergency: + return + if emergency == lib.emergency_stop: + __all_off() + __start_emergency_stop(bot, g_duration_update) + + +def __start_emergency_stop(bot, update): + global emergency_job + emergency_job = jq.run_once(__job_stop_and_restart, 0, context=update) + logging.info("Initialize emergency stop immediately.") + return + + # timer -def _start_standby_timer(bot, update): +def __start_standby_timer(bot, update): global timer_job - timer_job = jq.run_once(_job_timeout_reached, conf.standby_timeout, context=update) - logging.info("Init standby timer, added to queue.") + timer_job = jq.run_once(__job_stop_and_restart, conf.standby_timeout, context=update) + logging.info("Init standby timer of {0} seconds, added to queue.".format(conf.standby_timeout)) return -def _stop_standby_timer(bot, update): +def __stop_standby_timer(bot, upadate): timer_job.schedule_removal() - logging.info("Timer job removed of queue.") + logging.info("Timer job removed from the queue.") return -def _job_timeout_reached(bot, job): - timeout.timeout_reached(job.context) - logging.info("Timeout of {} seconds reached.".format(str(conf.standby_timeout))) +def __job_stop_and_restart(bot, job): + logging.warning("Job: Stop and restart called!") + stop_and_restart.stop_and_restart(job.context) return # error -def _error(bot, update, e): - logging.error('An error occurs! ' + str(e)) +def __error(bot, update, e): + logging.error('Update "{0}" caused error "{1}"'.format(update, e)) display.show_error() - _cam_off() + __cam_off() conf.GPIO.cleanup() return ConversationHandler.END # time stamps -def _timestamp(): - return conf.get_timestamp_line() +def __timestamp(): + return utils.get_timestamp_line() -def _start_time(): - return conf.get_timestamp() +def __start_time(): + return utils.get_timestamp() # camera -def _cam_on(): +def __cam_on(): logging.info('Enable camera module.') os.system(conf.enable_camera) return -def _cam_off(): +def __cam_off(): logging.info('Disable camera module.') os.system(conf.disable_camera) return def main(): - _init_bot_set_pins() + __init_bot_set_pins() + global updater updater = Updater(token) global jq @@ -363,11 +422,13 @@ def main(): dp = updater.dispatcher + emergency_stop_handler = RegexHandler('^{0}$'.format(str(lib.emergency_stop)), + __emergency_stop_handler, + pass_chat_data=True) ch = ConversationHandler( - entry_points=[CommandHandler('start', _start)], - + entry_points=[CommandHandler('start', __start)], states={ - SELECT: [RegexHandler( + SELECTION: [RegexHandler( '^({0}|{1}|{2}|{3}|{4}|{5}|{6}|{7}|{8}|{9}|{10}|{11}|{12}|{13}|{14})$'.format( str(lib.group1[0]), str(lib.group1[1]), @@ -383,20 +444,19 @@ def main(): str(lib.all_channels), str(lib.panic), str(lib.live_stream), - str(lib.reload)), _selection), - RegexHandler('^{0}$'.format(lib.stop_bot), _stop)], - - DURATION: [RegexHandler('^([0-9]+|{0}|{1})$'.format(str(lib.cancel), str(lib.panic)), _duration), - RegexHandler('^{0}$'.format(lib.stop_bot), _stop)] - - }, - fallbacks=[CommandHandler('stop', _stop)], + str(lib.reload)), __selection), + RegexHandler('^{0}$'.format(lib.stop_bot), __stop)], + DURATION: [RegexHandler('^([0-9]+|{0}|{1})$'.format(str(lib.cancel), str(lib.panic)), __duration), + RegexHandler('^{0}$'.format(lib.stop_bot), __stop)] + }, + fallbacks=[CommandHandler('stop', __stop)] ) + dp.add_handler(emergency_stop_handler) dp.add_handler(ch) - dp.add_error_handler(_error) + dp.add_error_handler(__error) updater.start_polling() diff --git a/bot/logger/__init__.py b/bot/logger/__init__.py index 26346d7..8e17c72 100644 --- a/bot/logger/__init__.py +++ b/bot/logger/__init__.py @@ -1,2 +1,3 @@ -import logging +from .logger import get_logger +from .logger import logging logging.getLogger(__name__).addHandler(logging.NullHandler()) diff --git a/bot/logger/logger.ini b/bot/logger/logger.ini new file mode 100644 index 0000000..4d3d77c --- /dev/null +++ b/bot/logger/logger.ini @@ -0,0 +1,35 @@ +[loggers] +keys=root + +[handlers] +# keys=file_handler +keys=stream_handler,file_handler + +[formatters] +# keys=file +keys=console,file + +[logger_root] +level=DEBUG +# handlers=file_handler +handlers=stream_handler,file_handler + +[handler_stream_handler] +# class=StreamHandler +class=FileHandler +level=DEBUG +formatter=console +# args=(sys.stderr,) +args=('/greenhouse_console.log',) + +[handler_file_handler] +class=FileHandler +level=INFO +formatter=file +args=('/greenhouse.log',) + +[formatter_console] +format=%(asctime)s %(levelname)-8s %(name)-15s %(module)-20s > %(message)s + +[formatter_file] +format=%(asctime)s | %(levelname)-8s | %(module)-20s %(threadName)-38s > %(message)s diff --git a/bot/logger/logger.py b/bot/logger/logger.py index eccd4a5..366c62d 100644 --- a/bot/logger/logger.py +++ b/bot/logger/logger.py @@ -8,14 +8,14 @@ from logging.config import fileConfig this_folder = os.path.dirname(os.path.abspath(__file__)) -config_file = os.path.join(this_folder, 'logger_config.ini') +config_file = os.path.join(this_folder, 'logger.ini') fileConfig(config_file) def get_logger(name=None): if name is None: name = __name__ - logger = logging.getLogger(name) + logger = logging.getLogger(name[0:15]) return logger diff --git a/bot/logger/logger_config.ini b/bot/logger/logger_config.ini deleted file mode 100644 index 48e70b2..0000000 --- a/bot/logger/logger_config.ini +++ /dev/null @@ -1,34 +0,0 @@ -[loggers] -keys=root - -[handlers] -keys=file_handler -# keys=stream_handler,file_handler - -[formatters] -keys=file -# keys=console,file - -[logger_root] -level=DEBUG -handlers=file_handler -# handlers=stream_handler,file_handler - -# [handler_stream_handler] -# class=StreamHandler -# level=INFO -# formatter=console -# args=(sys.stderr,) - -[handler_file_handler] -class=FileHandler -level=INFO -formatter=file -args=('/greenhouse.log',) - -# [formatter_console] -# format=%(asctime)s | %(levelname)-8s | %(name)-15s | %(threadName)s %(module)-20s | %(message)s -# datefmt= - -[formatter_file] -format=%(asctime)s | %(levelname)-8s | %(name)-15s | %(threadName)-10s - %(module)-20s > %(message)s diff --git a/bot/peripherals/dht/dht.py b/bot/peripherals/dht/dht.py index f2e3e52..9611f0e 100644 --- a/bot/peripherals/dht/dht.py +++ b/bot/peripherals/dht/dht.py @@ -8,7 +8,7 @@ import conf.greenhouse_config as conf import logger.logger as log -logging = log.get_logger('dht') +logging = log.get_logger() lib = conf.lib sensor = Adafruit_DHT.DHT22 diff --git a/bot/peripherals/four_digit/four_digits.py b/bot/peripherals/four_digit/four_digits.py index 7ce5cca..ecfefa4 100644 --- a/bot/peripherals/four_digit/four_digits.py +++ b/bot/peripherals/four_digit/four_digits.py @@ -10,9 +10,10 @@ from __future__ import absolute_import import math -import conf.greenhouse_config as conf +import utils.utils as utils from time import sleep - +import logger.logger as log +logger = log.get_logger() """ http://www.uize.com/examples/seven-segment-display.html """ # 0 1 2 3 4 5 6 7 8 9 @@ -34,8 +35,9 @@ class TM1637: + logger.info('Init pin settings for 4-digit-display!') global IO - IO = conf.set_pins() + IO = utils.set_pins() __double_point = False __clk_pin = 0 __data_pin = 0 diff --git a/bot/peripherals/gpio_check.py b/bot/peripherals/gpio_check.py index e9e369c..5d781bf 100644 --- a/bot/peripherals/gpio_check.py +++ b/bot/peripherals/gpio_check.py @@ -7,7 +7,7 @@ import sys import logger.logger as log -logging = log.get_logger('GPIO check') +logging = log.get_logger() pin_to_check = int(sys.argv[1]) gpios = (21, 22, 23, 24, 25, 27, 28, 29) diff --git a/bot/peripherals/oled/display.py b/bot/peripherals/oled/display.py index e902a90..1cb8b3f 100644 --- a/bot/peripherals/oled/display.py +++ b/bot/peripherals/oled/display.py @@ -8,6 +8,7 @@ from lib_oled96 import Ssd1306 from smbus import SMBus + # Display setup, methods and members """ 0 = Raspberry Pi 1, 1 = Raspberry Pi > 1 """ i2cbus = SMBus(1) @@ -19,12 +20,28 @@ switch_time = 15 +"""Ensure same file names in update_bot.sh!""" def get_last_commit(): - commit = open("/lastGreenhouseCommit.id").read() - branch = open("/defaultGreenhouseBranch.name").read() - commit = commit[0:6] - commit = commit + " " + branch.replace("\n", "") - return commit + commit = None + branch = None + + try: + commit = open("/greenhouseRepoCommit.id").read() + if commit is None: + commit = '-------' + else: + commit = commit[0:7] + branch = open("/greenhouseRepoBranch.name").read() + if branch is None: + branch = '-------' + else: + branch = branch.replace("\n", "") + except Exception: + build = '!!!ERROR!!!' + return build + + build = commit + " " + branch + return build def get_core_temp(): diff --git a/bot/peripherals/temperature.py b/bot/peripherals/temperature.py index 6835b3b..a103aec 100644 --- a/bot/peripherals/temperature.py +++ b/bot/peripherals/temperature.py @@ -6,7 +6,7 @@ import conf.greenhouse_config as conf import logger.logger as log -logging = log.get_logger('temperature') +logging = log.get_logger() temp = 0 one = 0 diff --git a/bot/test_bot.py b/bot/test_bot.py deleted file mode 100644 index e03f667..0000000 --- a/bot/test_bot.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -"""Basic example for a bot that uses inline keyboards. -# This program is dedicated to the public domain under the CC0 license. -""" - -from __future__ import absolute_import -import conf.greenhouse_config as conf -from telegram import InlineKeyboardButton, InlineKeyboardMarkup -from telegram.ext import Updater, CommandHandler, CallbackQueryHandler -import logger.logger as log - -logger = log.get_logger('test bot') - - -def start(bot, update): - keyboard = [[InlineKeyboardButton("Option 1", callback_data='1'), - InlineKeyboardButton("Option 2", callback_data='2')], - - [InlineKeyboardButton("Option 3", callback_data='3')]] - - reply_markup = InlineKeyboardMarkup(keyboard) - - update.message.reply_text('Please choose:', reply_markup=reply_markup) - - -def button(bot, update): - query = update.callback_query - - bot.edit_message_text(text="Selected option: {}".format(query.data), - chat_id=query.message.chat_id, - message_id=query.message.message_id) - - -def help(bot, update): - update.message.reply_text("Use /start to test this bot.") - - -def error(bot, update, error): - """Log Errors caused by Updates.""" - logger.warning('Update "%s" caused error "%s"', update, error) - - -def main(): - # Create the Updater and pass it your bot's token. - updater = Updater(conf.token) - - updater.dispatcher.add_handler(CommandHandler('start', start)) - updater.dispatcher.add_handler(CallbackQueryHandler(button)) - updater.dispatcher.add_handler(CommandHandler('help', help)) - updater.dispatcher.add_error_handler(error) - - # Start the Bot - updater.start_polling() - - # Run the bot until the user presses Ctrl-C or the process receives SIGINT, - # SIGTERM or SIGABRT - updater.idle() - - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/bot/update_bot.sh b/bot/update_bot.sh index 8dca63c..3ab84f5 100644 --- a/bot/update_bot.sh +++ b/bot/update_bot.sh @@ -7,8 +7,9 @@ chat=$2 project=greenhouse owner=kaulketh log='/update_bot.log' -commit_id='/lastGreenhouseCommit.id' -cloned_branch='/defaultGreenhouseBranch.name' +### Ensure same file names in peripherals/oled/display.py! ### +commit_id='/greenhouseRepoCommit.id' +cloned_branch='/greenhouseRepoBranch.name' bot_dir='/home/pi/scripts/TelegramBot/' wait=3 @@ -18,13 +19,15 @@ echo "Failed! Paremeter is missing." echo "Usage only possible at least with Telegram bot API token and Chat ID!" } + # if less than 2 arguments supplied, display usage if [[ $# -le 1 ]] - then - display_usage - exit 1 + then + display_usage + exit 1 fi + # if third arguments supplied then will set as branch if [[ $# -eq 3 ]] then @@ -34,9 +37,9 @@ else # get default branch from repository branch=$(curl -s https://api.github.com/repos/${owner}/${project} --insecure | grep -Po '(?<="default_branch":)(.*?)(?=,)' | sed "s/\"//g" | sed -e 's/^[[:space:]]*//') echo ${branch} > ${cloned_branch} - fi + # get last commit id of branch commit=$(curl -s https://api.github.com/repos/${owner}/${project}/commits/${branch} --insecure | grep -Po '(?<="sha":)(.*?)(?=,)' -m 1 | sed "s/\"//g" | sed -e 's/^[[:space:]]*//' | sed -e 's/[.]*$//') # get saved commit diff --git a/bot/utils/__init__.py b/bot/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bot/peripherals/timeout.py b/bot/utils/stop_and_restart.py similarity index 76% rename from bot/peripherals/timeout.py rename to bot/utils/stop_and_restart.py index 4ddaf2f..d9a264b 100644 --- a/bot/peripherals/timeout.py +++ b/bot/utils/stop_and_restart.py @@ -12,14 +12,14 @@ import peripherals.four_digit.display as display import logger.logger as log -logging = log.get_logger('timeout') +logging = log.get_logger() # API token and chat Id token = conf.token chat_id = conf.mainId -def _read_cmd(cmd): +def __read_cmd(cmd): os.system(cmd + ' > ' + lib.tmp_file + ' 2>&1') file = open(lib.tmp_file, 'r') data = file.read() @@ -27,18 +27,18 @@ def _read_cmd(cmd): return data -def timeout_reached(update): - logging.info('Timeout reached, set bot in standby.') - _read_cmd(conf.disable_camera) +def stop_and_restart(update): + logging.warning('Stop and restart, set bot in standby.') + __read_cmd(conf.disable_camera) display.show_stop() time.sleep(2) # start new new instance of greenhouse - _read_cmd(lib.restart_bot) + __read_cmd(lib.restart_bot) update.message.reply_text(conf.lib.msg_stop, parse_mode=ParseMode.MARKDOWN, reply_markup=ReplyKeyboardRemove()) display.show_standby() # kill the current instance of greenhouse bot - pid1 = _read_cmd(lib.get_pid1) - _read_cmd('kill -9 {0}'.format(str(pid1))) + pid1 = __read_cmd(lib.get_pid1) + __read_cmd('kill -9 {0}'.format(str(pid1))) return diff --git a/bot/utils/utils.py b/bot/utils/utils.py new file mode 100644 index 0000000..099cc99 --- /dev/null +++ b/bot/utils/utils.py @@ -0,0 +1,59 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# useful methods +# author: Thomas Kaulke, kaulketh@gmail.com + +from __future__ import absolute_import +import time +import RPi.GPIO as GPIO +import logger.logger as log + +"""logging is configured in logger package in logger.ini""" +logging = log.get_logger() + +# switch functions +def switch_on(pin): + logging.info('switch on: ' + str(pin)) + GPIO.setup(pin, GPIO.OUT) + GPIO.output(pin, GPIO.LOW) + # os.system(run_gpio_check + str(pin)) + return + + +def switch_off(pin): + logging.info('switch off: ' + str(pin)) + GPIO.setup(pin, GPIO.OUT) + GPIO.output(pin, GPIO.HIGH) + # os.system(run_gpio_check + str(pin)) + GPIO.cleanup(pin) + return + + +# date time strings +def get_timestamp(): + return time.strftime('[%d.%m.%Y %H:%M:%S] ') + + +def get_timestamp_line(): + return time.strftime('`[%d.%m.%Y %H:%M:%S]\n---------------------\n`') + + +# gets the state of pin, if 0 is switched on +def get_pin_state(pin): + GPIO.setup(pin, GPIO.OUT) + return GPIO.input(pin) + + +# to use Raspberry Pi board pin numbers +def set_pins(): + GPIO.setmode(GPIO.BOARD) + logging.info('Set GPIO mode: GPIO.BOARD') + # to use GPIO instead board pin numbers, then please adapt pin definition + # GPIO.setmode(GPIO.BCM) + # comment if warnings required + GPIO.setwarnings(False) + return GPIO + + +if __name__ == '__main__': + pass \ No newline at end of file