예제 #1
0
def set_amp_power(power_state, relay_name, amp_zone_index):
    try:
        relay = models.ZoneCustomRelay.query.filter_by(relay_pin_name=relay_name).first()
        power_state = bool(power_state)
        if relay is not None:
            initial_relay_state = relay.relay_is_on
            # power on main relay for amp or on/off if there is no zone
            if power_state is True or amp_zone_index == 0:
                relay.relay_is_on = power_state
                commit()
                # dispatch as UI action otherwise change actions are not triggered
                dispatcher.send(signal=Constant.SIGNAL_UI_DB_POST, model=models.ZoneCustomRelay, row=relay)
                msg = "Set relay {} to state {} zone_index={}\n".format(relay_name, power_state, amp_zone_index)
                #L.l.debug(msg)
            else:
                msg = "Not changed relay state for {}\n".format(relay_name)
        else:
            msg = "Could not find relay name {}\n".format(relay_name)
            L.l.warning(msg)
            return msg

        # change amp zone power
        if amp_zone_index is None or amp_zone_index == 0:
            # only main relay change is needed
            return msg + "Power in {} set to {}\n".format(relay_name, relay.relay_is_on)
        else:
            # potentially amp settings change is required to switch amp zones
            if initial_relay_state is not True and power_state is True:
                # delay to wait for amp to fully start
                time.sleep(5)
            result_amp = amp_zone_power(power_state, amp_zone_index)
            return msg + result_amp
    except Exception as ex:
        L.l.error("Error set_amp_power {}".format(ex))
        return "Error set_amp_power {}".format(ex)
예제 #2
0
def setup_in_ports(gpio_pin_list):
    # Log.logger.info('Socket timeout={}'.format(socket.getdefaulttimeout()))
    # socket.setdefaulttimeout(None)
    global __callback, __pi
    L.l.info('Configuring {} gpio input ports'.format(len(gpio_pin_list)))
    if __pi:
        if socket.getdefaulttimeout() is not None:
            L.l.critical('PiGpio callbacks cannot be started as socket timeout is not None')
        else:
            for gpio_pin in gpio_pin_list:
                if gpio_pin.pin_type == Constant.GPIO_PIN_TYPE_PI_STDGPIO:
                    try:
                        L.l.info('Set pincode={} type={} index={} as input'.format(gpio_pin.pin_code,
                                                                                   gpio_pin.pin_type,
                                                                                   gpio_pin.pin_index_bcm))
                        __pi.set_mode(int(gpio_pin.pin_index_bcm), pigpio.INPUT)
                        # https://learn.sparkfun.com/tutorials/pull-up-resistors
                        __pi.set_pull_up_down(int(gpio_pin.pin_index_bcm), pigpio.PUD_UP)
                        __callback.append(__pi.callback(user_gpio=int(gpio_pin.pin_index_bcm),
                                                        edge=pigpio.EITHER_EDGE, func=input_event))
                        gpio_pin_record = models.GpioPin().query_filter_first(
                            models.GpioPin.pin_code.in_([gpio_pin.pin_code]),
                            models.GpioPin.host_name.in_([Constant.HOST_NAME]))
                        gpio_pin_record.pin_direction = Constant.GPIO_PIN_DIRECTION_IN
                        commit()
                    except Exception, ex1:
                        L.l.critical('Unable to setup pigpio_gpio pin, er={}'.format(ex1))
                else:
                    L.l.info('Skipping PiGpio setup for pin {} with type {}'.format(gpio_pin.pin_code,
                                                                                    gpio_pin.pin_type))
        L.l.info('Exit gpio callback thread loop')
예제 #3
0
파일: api_v1.py 프로젝트: zorro2000se/haiot
def generic_db_update(model_name, filter_name, filter_value, field_name, field_value):
    try:
        L.l.info("Execute API generic_db_update model={} filter={} filtervalue={} field={} fieldvalue={}"
                 .format(model_name, filter_name, filter_value, field_name, field_value))
        table = utils.class_for_name('main.admin.models', model_name)
        # http://stackoverflow.com/questions/19506105/flask-sqlalchemy-query-with-keyword-as-variable
        kwargs = {filter_name: filter_value}
        # avoid getting "This session is in 'committed' state; no further SQL can be emitted within this transaction"
        db.session.remove()
        # db.session = db.create_scoped_session()
        record = table.query.filter_by(**kwargs).first()
        if record:
            if hasattr(record, field_name):
                setattr(record, field_name, field_value)
                db.session.add(record)
                commit()
                # dispatch as UI action otherwise change actions are not triggered
                dispatcher.send(signal=Constant.SIGNAL_UI_DB_POST, model=table, row=record)
                return '%s: %s' % (Constant.SCRIPT_RESPONSE_OK, record)
            else:
                msg = 'Field {} not found in record {}'.format(field_name, record)
                L.l.warning(msg)
                return '%s: %s' % (Constant.SCRIPT_RESPONSE_NOTOK, msg)
        else:
            msg = 'No records returned for filter_name={} and filter_value={}'.format(filter_name, filter_value)
            L.l.warning(msg)
            return '%s: %s' % (Constant.SCRIPT_RESPONSE_NOTOK, msg)
    except Exception as ex:
        msg = 'Exception on /apiv1/db_update: {}'.format(ex)
        L.l.error(msg, exc_info=1)
        return '%s: %s' % (Constant.SCRIPT_RESPONSE_NOTOK, msg)
    finally:
        # db.session.remove()
        pass
예제 #4
0
def record_update(obj_dict=None):
    if not obj_dict:
        obj_dict = {}
    try:
        source_host_name = utils.get_object_field_value(
            obj_dict, Constant.JSON_PUBLISH_SOURCE_HOST)
        zone_id = utils.get_object_field_value(
            obj_dict, utils.get_model_field_name(models.ZoneHeatRelay.zone_id))
        pin_name = utils.get_object_field_value(
            obj_dict,
            utils.get_model_field_name(models.ZoneHeatRelay.heat_pin_name))
        is_on = utils.get_object_field_value(
            obj_dict,
            utils.get_model_field_name(models.ZoneHeatRelay.heat_is_on))
        # fixme: remove hard reference to object field
        sent_on = utils.get_object_field_value(obj_dict, "event_sent_datetime")
        L.l.debug(
            'Received heat relay update from {} zoneid={} pin={} is_on={} sent={}'
            .format(source_host_name, zone_id, pin_name, is_on, sent_on))
        zone_heat_relay = models.ZoneHeatRelay.query.filter_by(
            zone_id=zone_id).first()
        if zone_heat_relay:
            gpio_host_name = zone_heat_relay.gpio_host_name
            cmd_heat_is_on = utils.get_object_field_value(
                obj_dict,
                utils.get_model_field_name(models.ZoneHeatRelay.heat_is_on))
            L.l.debug(
                'Local heat state zone_id {} must be changed to {} on pin {}'.
                format(zone_id, cmd_heat_is_on, zone_heat_relay.gpio_pin_code))
            if cmd_heat_is_on:
                pin_value = 1
            else:
                pin_value = 0
            # set pin only on pins owned by this host
            if zone_heat_relay and gpio_host_name == Constant.HOST_NAME:
                L.l.info("Setting heat pin {} to {}".format(
                    zone_heat_relay.gpio_pin_code, pin_value))
                pin_state = gpio.relay_update(
                    gpio_pin_code=zone_heat_relay.gpio_pin_code,
                    pin_value=pin_value)
            else:
                pin_state = pin_value
            if pin_state == pin_value:
                pin_state = (pin_state == 1)
                zone_heat_relay.heat_is_on = pin_state
                zone_heat_relay.notify_transport_enabled = False
                commit()
            else:
                L.l.warning(
                    'Heat state zone_id {} unexpected val={} after setval={}'.
                    format(zone_id, pin_state, pin_value))
        else:
            L.l.warning(
                'No heat relay defined for zone {}, db data issue?'.format(
                    zone_id))
    except Exception as ex:
        L.l.warning('Error updating heat relay state, err {}'.format(ex))
예제 #5
0
def get_pin_bcm(bcm_id=''):
    '''BCM pin id format. Return value is 0 or 1.'''
    if not __is_pin_setup(bcm_id):
        __set_pin_dir_in(bcm_id)
    if __is_pin_setup(bcm_id):
        pin_value = __read_line(bcm_id)
        gpio_pin = models.GpioPin.query.filter_by(pin_index_bcm=bcm_id, host_name=Constant.HOST_NAME).first()
        if gpio_pin:
            gpio_pin.pin_value = pin_value
            commit()
        return pin_value
    else:
        L.l.critical('Unable to get pin bcm {}'.format(bcm_id))
예제 #6
0
def __set_pin_dir_in(bcm_id=''):
    try:
        # file = open('/sys/class/gpio/gpio{}/direction'.format(bcm_id), 'a')
        # print >> file, 'in'
        # file.close()
        __setup_pin(bcm_id)
        if __write_to_file_as_root(file='/sys/class/gpio/gpio{}/direction'.format(bcm_id), value='in'):
            L.l.info('Set pin {} direction IN is OK'.format(bcm_id))
            gpio_pin = __get_gpio_db_pin(bcm_id)
            if gpio_pin:
                gpio_pin.pin_direction = 'in'
                commit()
        return True
    except Exception, ex:
        L.l.warning('Unexpected exception on pin {} direction IN set, err {}'.format(bcm_id, ex))
        return False
예제 #7
0
def __is_pin_setup(bcm_id=''):
    try:
        file = open('/sys/class/gpio/gpio{}/value'.format(bcm_id), 'r')
        file.close()
        gpio_pin = models.GpioPin.query.filter_by(pin_index_bcm=bcm_id, host_name=Constant.HOST_NAME).first()
        if gpio_pin and not gpio_pin.is_active:
            L.l.warning(
                'Gpio pin={} is used not via me, conflict with ext. apps or unclean stop?'.format(bcm_id))
            gpio_pin.is_active = True
            commit()
        return True
    except IOError:
        return False
    except Exception, ex:
        L.l.warning('Unexpected exception on pin setup check, err {}'.format(ex))
        db.session.rollback()
        return False
예제 #8
0
def __save_heat_state_db(zone, heat_is_on):
    assert isinstance(zone, models.Zone)
    zone_heat_relay = models.ZoneHeatRelay.query.filter_by(
        zone_id=zone.id).first()
    if zone_heat_relay is not None:
        zone_heat_relay.heat_is_on = heat_is_on
        zone_heat_relay.updated_on = utils.get_base_location_now_date()
        L.l.debug(
            'Heat state changed to is-on={} via pin={} in zone={}'.format(
                heat_is_on, zone_heat_relay.heat_pin_name, zone.name))
        zone_heat_relay.notify_transport_enabled = True
        zone_heat_relay.save_to_graph = True
        zone_heat_relay.save_to_history = True
        # save latest heat state for caching purposes
        zone.heat_is_on = heat_is_on
        zone.last_heat_status_update = utils.get_base_location_now_date()
        commit()
    else:
        L.l.warning('No heat relay found in zone {}'.format(zone.name))
예제 #9
0
def handle_event_alarm(gpio_pin_code='',
                       direction='',
                       pin_value='',
                       pin_connected=None):
    zonealarm = models.ZoneAlarm.query.filter_by(
        gpio_pin_code=gpio_pin_code,
        gpio_host_name=Constant.HOST_NAME).first()
    if zonealarm is not None:
        zonearea = models.ZoneArea().query_filter_first(
            models.ZoneArea.zone_id == zonealarm.zone_id)
        if zonearea is not None:
            area = models.Area().query_filter_first(
                models.Area.id == zonearea.area_id)
            if area is not None:
                zonealarm.start_alarm = area.is_armed
                zone = models.Zone.query.filter_by(
                    id=zonealarm.zone_id).first()
                if zone is not None:
                    dispatcher.send(signal=Constant.SIGNAL_ALARM,
                                    zone_name=zone.name,
                                    alarm_pin_name=zonealarm.alarm_pin_name,
                                    pin_connected=pin_connected)
                    # L.l.info('Got alarm {} zone={} pin={} pin_conn={} pin_value={} gpio={}'.format(
                    #    zone.name, zonealarm.zone_id, zonealarm.alarm_pin_name,
                    #    pin_connected, pin_value, gpio_pin_code))
                else:
                    L.l.error(
                        "Could not find zone for gpio pin {}, trigger actions could be missed"
                        .format(gpio_pin_code))
                zonealarm.alarm_pin_triggered = not pin_connected
                zonealarm.updated_on = utils.get_base_location_now_date()
                zonealarm.notify_transport_enabled = True
                commit()
            else:
                L.l.warning('Zone {} is mapped to missing area' %
                            zonealarm.zone_id)
        else:
            L.l.warning('Zone %s not mapped to an area' % zonealarm.zone_id)
    else:
        L.l.info('Mising zone alarm for gpio code {}'.format(gpio_pin_code))
예제 #10
0
def __update_zone_heat(zone, heat_schedule, sensor):
    heat_is_on = False
    main_source_needed = True
    try:
        minute = utils.get_base_location_now_date().minute
        hour = utils.get_base_location_now_date().hour
        weekday = datetime.datetime.today().weekday()
        # todo: insert here auto heat change based on presence status
        if weekday <= 4:  # Monday=0
            schedule_pattern = models.SchedulePattern.query.filter_by(
                id=heat_schedule.pattern_week_id).first()
        else:
            schedule_pattern = models.SchedulePattern.query.filter_by(
                id=heat_schedule.pattern_weekend_id).first()
        if schedule_pattern:
            main_source_needed = schedule_pattern.main_source_needed
            if main_source_needed is False:
                L.l.info(
                    "Main heat source is not needed for zone {}".format(zone))
            force_off = False
            # set heat to off if condition is met (i.e. do not try to heat water if heat source is cold)
            if schedule_pattern.activate_on_condition:
                relay_name = schedule_pattern.activate_condition_relay
                zone_heat_relay = models.ZoneHeatRelay.query.filter_by(
                    heat_pin_name=relay_name).first()
                if zone_heat_relay is not None:
                    force_off = zone_heat_relay.heat_is_on is False
                    if force_off:
                        L.l.info(
                            'Deactivating heat in zone {} due to relay {}'.
                            format(zone, zone_heat_relay))
                else:
                    L.l.error('Could not find the heat relay for zone heat {}'.
                              format(zone))
            # strip formatting characters that are not used to represent target temperature
            pattern = str(schedule_pattern.pattern).replace('-', '').replace(
                ' ', '')
            # check pattern validity
            if len(pattern) == 24:
                temperature_code = pattern[hour]
                temperature_target = models.TemperatureTarget.query.filter_by(
                    code=temperature_code).first()
                # check if we need forced heat on, if for this hour temp has a upper target than min
                force_on = False
                if schedule_pattern.keep_warm:
                    if len(schedule_pattern.keep_warm_pattern) == 20:
                        interval = int(minute / 5)
                        delta_warm = sensor.temperature - temperature_target.target
                        if delta_warm <= P.MAX_DELTA_TEMP_KEEP_WARM:
                            force_on = (
                                (schedule_pattern.keep_warm_pattern[interval]
                                 == "1")
                                and temperature_code is not P.TEMP_NO_HEAT)
                        else:
                            L.l.info(
                                "Temperature is too high with delta {}, ignoring keep warm"
                                .format(delta_warm))
                    else:
                        L.l.critical(
                            "Missing keep warm pattern for zone {}".format(
                                zone.name))
                if temperature_target:
                    if zone.active_heat_schedule_pattern_id != schedule_pattern.id:
                        L.l.debug(
                            'Pattern in zone {} changed to {}, target={}'.
                            format(zone.name, schedule_pattern.name,
                                   temperature_target.target))
                        zone.active_heat_schedule_pattern_id = schedule_pattern.id
                    zone.heat_target_temperature = temperature_target.target
                    commit()
                    if sensor.temperature is not None:
                        heat_is_on = __decide_action(zone,
                                                     sensor.temperature,
                                                     temperature_target.target,
                                                     force_on=force_on,
                                                     force_off=force_off)
                    #else:
                    #    heat_is_on = zone.heat_is_on
                else:
                    L.l.critical('Unknown temperature pattern code {}'.format(
                        temperature_code))
            else:
                L.l.warning(
                    'Incorrect temp pattern [{}] in zone {}, length is not 24'.
                    format(pattern, zone.name))
    except Exception as ex:
        L.l.error('Error updatezoneheat, err={}'.format(ex, exc_info=True))
    #Log.logger.info("Temp in {} has target={} and current={}, heat should be={}".format(zone.name,
    #                                                                            zone.heat_target_temperature,
    #                                                                             sensor.temperature, heat_is_on))
    return heat_is_on, main_source_needed
예제 #11
0
def set_main_heat_source():
    heat_source_relay_list = models.ZoneHeatRelay.query.filter(
        models.ZoneHeatRelay.temp_sensor_name is not None).all()
    up_limit = P.temp_limit + P.threshold
    for heat_source_relay in heat_source_relay_list:
        # is there is a temp sensor defined, consider this source as possible alternate source
        if heat_source_relay.temp_sensor_name is not None:
            temp_rec = models.Sensor().query_filter_first(
                models.Sensor.sensor_name.in_(
                    [heat_source_relay.temp_sensor_name]))
            # if alternate source is valid
            # fixok: add temp threshold to avoid quick on/offs
            if temp_rec is not None \
                    and ((temp_rec.temperature >= up_limit and not heat_source_relay.is_alternate_source_switch)
                         or (temp_rec.temperature >= P.temp_limit and heat_source_relay.is_alternate_source_switch)):
                if heat_source_relay.is_alternate_source_switch:
                    # stop main heat source
                    heatrelay_main_source = models.ZoneHeatRelay.query.filter_by(
                        is_main_heat_source=1).first()
                    main_source_zone = models.Zone.query.filter_by(
                        id=heatrelay_main_source.zone_id).first()
                    __save_heat_state_db(zone=main_source_zone,
                                         heat_is_on=False)
                    # turn switch valve on to alternate position
                    switch_source_zone = models.Zone.query.filter_by(
                        id=heat_source_relay.zone_id).first()
                    __save_heat_state_db(zone=switch_source_zone,
                                         heat_is_on=True)
                else:
                    # mark this source as active, to be started when there is heat need
                    if heat_source_relay.is_alternate_heat_source is False:
                        L.l.info(
                            'Alternate heat source is active with temp={}'.
                            format(temp_rec.temperature))
                    heat_source_relay.is_alternate_heat_source = True
                commit()
            else:
                # if alternate source is no longer valid
                if heat_source_relay.is_alternate_source_switch:
                    # stop alternate heat source
                    #heatrelay_alt_source = models.ZoneHeatRelay.query.filter_by(is_alternate_heat_source=1).first()
                    #if heatrelay_alt_source is not None:
                    #    alt_source_zone = models.Zone.query.filter_by(id=heatrelay_alt_source.zone_id).first()
                    #    __save_heat_state_db(zone=alt_source_zone, heat_is_on=False)
                    # turn valve back to main position
                    switch_source_zone = models.Zone.query.filter_by(
                        id=heat_source_relay.zone_id).first()
                    __save_heat_state_db(zone=switch_source_zone,
                                         heat_is_on=False)
                else:
                    # mark this source as inactive, let main source to start
                    if heat_source_relay.is_alternate_heat_source:
                        # force alt source shutdown if was on
                        alt_source_zone = models.Zone.query.filter_by(
                            id=heat_source_relay.zone_id).first()
                        __save_heat_state_db(zone=alt_source_zone,
                                             heat_is_on=False)
                        # todo: sleep needed to allow for valve return
                    if heat_source_relay.is_alternate_heat_source is True:
                        L.l.info(
                            'Alternate heat source is now inactive, temp source is {}'
                            .format(temp_rec))
                    heat_source_relay.is_alternate_heat_source = False
                commit()
예제 #12
0
def update_master_state():
    master_overall_selected = False
    try:
        alive_date_time = utils.get_base_location_now_date(
        ) - datetime.timedelta(minutes=1)
        node_list = models.Node.query.order_by(models.Node.priority).all()
        for node in node_list:
            #if recently alive, in order of id prio
            if node.updated_on >= alive_date_time and (
                    not master_overall_selected):
                if node.is_master_overall:
                    L.l.debug(
                        'Node {} is already master, all good we have a master'.
                        format(node.name))
                    master_overall_selected = True
                else:
                    L.l.info('Node {} will become a master'.format(node.name))
                    if node.name == Constant.HOST_NAME:
                        node.is_master_overall = True
                        node.notify_enabled_ = True
                        commit()
                    master_overall_selected = True
            else:
                if master_overall_selected and node.is_master_overall:
                    L.l.debug(
                        'Node {} should lose master status, if alive'.format(
                            node.name))
                    if node.name == Constant.HOST_NAME:
                        node.is_master_overall = False
                        node.notify_enabled_ = True
                        commit()
            # applying node master status locally, if changed in db
            if node.name == Constant.HOST_NAME:
                variable.NODE_THIS_IS_MASTER_LOGGING = node.is_master_logging

                if variable.NODE_THIS_IS_MASTER_OVERALL != node.is_master_overall:
                    if not node.is_master_overall:
                        # disabling local mastership immediately
                        variable.NODE_THIS_IS_MASTER_OVERALL = node.is_master_overall
                        L.l.info(
                            'Immediate change in node mastership, local node is master={}'
                            .format(variable.NODE_THIS_IS_MASTER_OVERALL))
                    else:
                        global since_when_i_should_be_master
                        # check seconds lapsed since cluster agreed I must be or lose master
                        seconds_elapsed = (
                            utils.get_base_location_now_date() -
                            since_when_i_should_be_master).total_seconds()
                        if check_if_no_masters_overall(
                        ) or seconds_elapsed > 10:
                            variable.NODE_THIS_IS_MASTER_OVERALL = node.is_master_overall
                            L.l.info(
                                'Change in node mastership, local node is master={}'
                                .format(variable.NODE_THIS_IS_MASTER_OVERALL))
                            since_when_i_should_be_master = datetime.datetime.max
                        else:
                            # L.l.info('Waiting to set master status, sec. lapsed={}'.format(seconds_elapsed))
                            pass
                        if not variable.NODE_THIS_IS_MASTER_OVERALL:
                            # record date when cluster agreed I must be master
                            if since_when_i_should_be_master == datetime.datetime.max:
                                since_when_i_should_be_master = utils.get_base_location_now_date(
                                )
    except Exception as ex:
        L.l.warning('Error try_become_master, err {}'.format(ex))