def create_camera(name: str, camera_device_id: int, timer: list, resolution: dict, trimming: dict) -> None: cameras = get_camera_config() tank_id = get_config_item('TANK_ID') camera_id = generate_camera_id(tank_id) new_camera = { 'camera_id': camera_id, 'name': name, 'camera_device_id': camera_device_id, 'resolution': { 'x': resolution['x'], 'y': resolution['y'], }, 'timer': list(timer), 'trimming': { 'top': trimming['top'], 'bottom': trimming['bottom'], 'left': trimming['left'], 'right': trimming['right'], }, 'latest_picture_url': '' } cameras.append(new_camera) set_camera_config(cameras) logger( INFO, 'Create new camera 📸\n' + json.dumps(new_camera), True, False ) return
def post_slack_with_attachment( channel: str, username: str, text: str, icon_emoji: str, color: str, attachment_title: str, attachment_text: str, attachment_footer: str, ) -> None: post_data = { "channel": channel, "username": username, "text": text, "icon_emoji": icon_emoji, "attachments": [{ "color": color, "author_name": attachment_title, "text": attachment_text, "footer": attachment_footer, }] } slack_webhook_url = get_config_item('SLACK')['WEBHOOK_URL'] response = requests.post(slack_webhook_url, data=json.dumps(post_data))
def auto_feeder(pin: int) -> bool: """ auto feeder Parameters ---------- pin : int target gpio (BCM) Returns ------- bool Auto feeding successful """ is_running = gpio_read(pin) if is_running: return False AUTO_FEEDER_RUN_TIME = get_config_item('DEVICE')['AUTO_FEEDER_RUN_TIME'] # auto feeder on gpio_write(pin, 1) try: publish_device_state() except: gpio_write(pin, 0) return False time.sleep(AUTO_FEEDER_RUN_TIME) # pump off gpio_write(pin, 0) publish_device_state() return True
def import_sensor_back_file(backup_file: list) -> None: MAX_SENSOR_NUMBER = get_config_item('MAX_SENSOR_NUMBER') if len(backup_file) != MAX_SENSOR_NUMBER: raise FormatInvalid('Device number invalid') # TODO Validation set_sensor_config(backup_file) return
def import_device_back_file(backup_file: list) -> None: MAX_DEVICE_NUMBER = get_config_item('MAX_DEVICE_NUMBER') if len(backup_file) != MAX_DEVICE_NUMBER: raise FormatInvalid('Device number invalid') # TODO Validation set_gpio_config(backup_file) return
def post_slack(channel: str, username: str, text: str, icon_emoji: str) -> None: post_data = { "channel": channel, "username": username, "text": text, "icon_emoji": icon_emoji } slack_webhook_url = get_config_item('SLACK')['WEBHOOK_URL'] response = requests.post(slack_webhook_url, data=json.dumps(post_data))
def logger(log_level: str, message: str, require_slack: bool = False, mention_required: bool = False) -> None: prefix = log_message_prefix_generator(log_level) # stdout print('{colored_prefix} {message}'.format(colored_prefix=color_text( text=prefix, color=LOG_LEVEL[log_level]['COLOR']), message=message)) # out to log file if LOG_LEVEL[log_level]['LEVEL'] >= MIN_FILE_OUTPUT_LEVEL: output_log_file(text=f'{prefix} {message}\n') # slack slack_notification = get_config_item('SLACK')['SLACK_NOTIFICATION'] if require_slack and slack_notification: mention = '' if log_level == ERROR or log_level == FATAL or mention_required: mention = SLACK_MENTION_TYPE['CHANNEL'] # Error handling is required in HTTP Request try: post_log_to_slack( pretext=mention, color=LOG_LEVEL[log_level]['SLACK_COLOR'], title=f'[{log_level}]', text=message, footer=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')) except Exception as e: error_message = ''.join( traceback.TracebackException.from_exception(e).format()) error_message += """ ----------------------------------------------- This message can not post to slack. {message} ----------------------------------------------- """.format(message=message) logger(ERROR, error_message) add_unsent_message( log_level=log_level, message=message, ) pass return
def post_log_to_slack(pretext: str, color: str, title: str, text: str, footer: str) -> None: # get slack config from config slack_config = get_config_item('SLACK') # post slack with attachment post_slack_with_attachment( channel=slack_config['LOG']['CHANNEL'], username=slack_config['LOG']['USERNAME'], text=pretext, icon_emoji=slack_config['LOG']['ICON_EMOJI'], color=color, attachment_title=title, attachment_text=text, attachment_footer=footer, )
def post_slack_by_type(text: str, type_: str) -> None: slack_config = get_config_item('SLACK') if type_ == SLACK_NOTIFICATION_TYPE['NOTIFICATION']: post_slack( channel=slack_config['NOTIFICATION']['CHANNEL'], username=slack_config['NOTIFICATION']['USERNAME'], text=slack_config['NOTIFICATION']['MESSAGE_FORMAT'].format( message=text), icon_emoji=slack_config['NOTIFICATION']['ICON_EMOJI'], ) elif type_ == SLACK_NOTIFICATION_TYPE['ERROR']: post_slack( channel=slack_config['ERROR']['CHANNEL'], username=slack_config['ERROR']['USERNAME'], text=slack_config['ERROR']['MESSAGE_FORMAT'].format(message=text), icon_emoji=slack_config['ERROR']['ICON_EMOJI'], ) else: raise NotificationTypeUndefined('This type does not exist.')
ls, make_dir, set_json_file, zero_padding, zero_padding_month, ) from service.logger import ( logger, DEBUG, INFO, WARN, ERROR, FATAL, ) AMS_ROOT_PATH = get_config_item('ROOT_PATH').rstrip('/') def get_camera_config_by_id(camera_id: str) -> dict: cameras = get_camera_config() for camera in cameras: if camera['camera_id'] == camera_id: return camera return {} def get_camera_device_config_by_id(camera_device_id: int) -> dict: camera_devices = get_camera_device_config() for camera_device in camera_devices: if camera_device['camera_device_id'] == camera_device_id: return camera_device return {}
def main(): PORT = get_config_item('port') app.run(debug=True, host='0.0.0.0', port=PORT)
def publish_sensor_data() -> None: sensing_config = get_config_item('SENSING') sensor_data_publish_period = sensing_config['SENSOR_DATA_PUBLISH_PERIOD'] sensing_number = sensing_config['SENSING_NUMBER'] sensor_config = get_sensor_config() total_value = {} for sensor in sensor_config: # if a sensor exists if sensor['sensor']: total_value[sensor['sensor_id']] = 0 for _ in range(sensing_number): for sensor_id in total_value.keys(): sensor_value = read_mcp(sensor_id) total_value[sensor_id] += sensor_value time.sleep(sensor_data_publish_period / sensing_number) publish_data = { "timestamp": int( datetime.datetime.now().strftime('%s') ), "sensors": [], } for sensor in sensor_config: # if a sensor does not exists if sensor['sensor'] == {}: continue # Least squares coefficients if len(sensor['sensor']['calibration']) > 1: a, b = least_squares( sensor['sensor']['calibration'] ) else: # use raw value a, b = 1, 0 publish_data['sensors'].append({ "sensor_id": sensor['sensor_id'], "name": sensor['sensor']['name'], "type": sensor['sensor']['type'], "value": round( a * total_value[sensor['sensor_id']] / sensing_number + b, 2), "raw_value": round(total_value[sensor['sensor_id']] / sensing_number, 1), }) publish_topic = publish_topics['SENSOR_DATA'] publish_data_json = json.dumps(publish_data) write_current_sensor_values(publish_data_json) publish( topic = publish_topic, message = publish_data_json, qos = 0, retain = True, ) print_color_log( title = LOG_TITLE['SENSOR'], title_color = Color.YELLOW, text = '{unixtime}: {topic}: {message}'.format( unixtime = datetime.datetime.now().strftime('%s'), topic = color_text(publish_topic, Color.GREEN), message = publish_data_json, ) )
from on_message.camera_album_get import get_album from on_message.camera_take_picture import camera_take_picture from service.device import get_all_device_state from service.sensor import get_current_sensor_values from service.backup import backup_file_name, get_device_backup_file, import_device_back_file, get_sensor_backup_file, import_sensor_back_file from service.logger import ( logger, DEBUG, INFO, WARN, ERROR, FATAL, ) app = Flask(__name__) server_config = get_config_item('LOCAL_SERVER') empty_response = json.dumps({}) class InvalidUsage(Exception): status_code = 400 def __init__(self, message, status_code=None, payload=None): Exception.__init__(self) self.message = message if status_code is not None: self.status_code = status_code self.payload = payload def to_dict(self):
"SLACK_COLOR": '#D7DF01', }, "ERROR": { "LEVEL": 4, "COLOR": Color.RED, "SLACK_COLOR": '#FF4000', }, "FATAL": { "LEVEL": 5, "COLOR": Color.PURPLE, "SLACK_COLOR": '#FF00BF', }, } MIN_FILE_OUTPUT_LEVEL = 2 AMS_ROOT_PATH = get_config_item('ROOT_PATH') OUTPUT_LOG_FILE_PATH = '/'.join([AMS_ROOT_PATH, 'log', 'logger']) UNSENT_LOG_FILE_PATH = '/'.join([AMS_ROOT_PATH, 'log', 'tmp', 'unsent.json']) def log_message_prefix_generator(log_level: str) -> str: """ Parameters ---------- text: log_level log level e.g. "INFO", "WARN", ... Returns ---------- str
from commons.consts import ( CRON_START_TEXT, CRON_END_TEXT, CRON_COMMENT_FORMAT, CRON_FORMAT_CONTINUOUS, CRON_FORMAT_DAILY, CRON_FORMAT_DISCREATE, DEVICE_RUN_TYPE, DEVICE_TYPE, ) from lib.config import get_gpio_config, get_config_item, get_root_path from lib.cron import get_crontab, write_to_crontab FEED_PUMP_DEFAULT_TIME = get_config_item('DEVICE')['FEED_PUMP_DEFAULT_TIME'] def cron_text_generator() -> str: """ This text is generated by this function. # ------ AMS start ------- # device_id: 1 # device_name: my_main_light # on 30 10 * * * gpio -g mode 26 out && gpio -g write 26 1 # off 30 18 * * * gpio -g mode 26 out && gpio -g write 26 0 # device_id: 2
import sys import pathlib current_dir = pathlib.Path(__file__).resolve().parent sys.path.append( str(current_dir) + '/../' ) from service.camera import take_picture from service.trimming import trimming from service.uploader import s3_upload, publish_picture from lib.config import get_config_item TMP_BASE_PICTURE_PATH = get_config_item('tmp_base_picture_path') TMP_TRIMMED_PICTURE_PATH = get_config_item('tmp_trimmed_picture_path') def picture(request: dict) -> None: # case no camera if len(request['cameras']) == 0: return take_picture( file_ = TMP_BASE_PICTURE_PATH, x = request['resolution']['x'], y = request['resolution']['y'], warm_up_time = request['cameraWarmUpTime'] ) for camera in request['cameras']: trimming( input_path = TMP_BASE_PICTURE_PATH, output_path = TMP_TRIMMED_PICTURE_PATH,