예제 #1
0
def plot_doorstate(args):
    """Generate plots."""
    resp = requests.get(
        args.url,
        params={
            'from':
            to_timestamp(datetime.now(tzlocal()) - timedelta(days=365))
        },
    )
    resp_json = _json_response_error_handling(resp)

    if not isinstance(resp_json, list):
        print('Invalid reponse from API:', resp_json)

    if args.plot_type == 'by-week':
        plot_by_week(resp_json, args.out)
    elif args.plot_type == 'by-hour':
        plot_by_hour(resp_json, args.out)
예제 #2
0
def update_doorstate():
    """Update doorstate (opened, close, ...)."""
    required_params = {'time', 'state', 'hmac'}

    data = request.json or request.form

    # validate
    try:
        for param in required_params:
            if not data.get(param, None):
                raise ValueError(param, 'Parameter is missing')
        if not hmac.compare_digest(
                calculate_hmac(data['time'], data['state'], ARGS.key),
                data['hmac']):
            raise ValueError(
                'hmac', 'HMAC digest is wrong. Do you have the right key?')
        if not data['time'].isnumeric():
            raise ValueError('time', 'Time has to be an integer timestamp.')
        time = datetime.fromtimestamp(int(data['time']), tzlocal())
        if abs(time - datetime.now(tzlocal())).total_seconds() > 60:
            raise ValueError(
                'time', 'Time is too far in the future or past. Use NTP!')
        if data['state'] not in DoorState.__members__:
            raise ValueError(
                'state', 'State has to be one of {}.'.format(', '.join(
                    DoorState.__members__.keys())))
        state = DoorState[data['state']]
        latest_door_state = OpeningPeriod.get_latest_state()
        if latest_door_state:
            if latest_door_state.state == state:
                # already opened/closed
                Event.touch_last_update()
                return jsonify({
                    'time':
                    latest_door_state.last_change_timestamp,
                    'state':
                    latest_door_state.state.name,
                    '_text':
                    'door was already {} at {}'.format(
                        latest_door_state.state.name,
                        latest_door_state.last_change_timestamp,
                    ),
                })
            elif latest_door_state.last_change_timestamp >= to_timestamp(time):
                raise ValueError('time',
                                 'New entry must be newer than latest entry.')
        elif state == DoorState.closed:
            # no entry: we assume the door was closed before -> already closed
            return jsonify({
                'time':
                0,
                'state':
                DoorState.closed.name,
                '_text':
                "door was already closed."
                " To be honest, we don't have any data yet but the first entry has to be 'opened'.",
            })
    except ValueError as err:
        abort(400, {err.args[0]: err.args[1]})

    # update doorstate
    if latest_door_state and latest_door_state.is_open and state == DoorState.closed:
        latest_door_state.closed = time
        APP.logger.debug(
            'Closing door. Resulting entry: open from %(opened)i till %(closed)i',
            latest_door_state.to_dict())
    elif (not latest_door_state
          or not latest_door_state.is_open) and state == DoorState.opened:
        latest_door_state = OpeningPeriod(opened=time)
        APP.logger.debug(
            'Opening door. New entry: open from %(opened)i till t.b.a.',
            latest_door_state.to_dict())
        DB.session.add(latest_door_state)
    else:
        abort(500, 'This should not happen')
    DB.session.commit()
    Event.touch_last_update()
    return jsonify({
        'time':
        latest_door_state.last_change_timestamp,
        'state':
        latest_door_state.state.name,
        '_text':
        'door is now {} (time: {})'.format(
            latest_door_state.state.name,
            latest_door_state.last_change_timestamp,
        ),
    })
예제 #3
0
 def last_change_timestamp(self):
     """Return the timestamp of the last change of this entry."""
     return to_timestamp(self.opened if self.is_open else self.closed)
예제 #4
0
 def closed_timestamp(self):
     """Return the integer timestamp for the closed time of this entry."""
     return to_timestamp(self.closed) if self.closed else None
예제 #5
0
 def opened_timestamp(self):
     """Return the integer timestamp for the opened time of this entry."""
     return to_timestamp(self.opened)