Пример #1
0
    def start_graph_live(self, a_ax):
        """
        main thread
        """
        #        print( f"start_graph_live in adapter {self.name} at {self.tcpip}" )
        #        msg    =  f"? ? start_graph_live for device: {self.name} "
        #        AppGlobal.what_thread( threading.get_ident(), msg, 20  )
        msg = "SmartPlugAdapter.start_graph_live  "
        AppGlobal.log_if_wrong_thread(threading.get_ident(),
                                      msg=msg,
                                      main=True)

        if not self.monitor:
            return

        if self.gd_time_adj is None:
            self.gd_time_adj = []
            self.gd_power = []

        #self.reset_graphing_data()   # why bother consider keeping data !!
        #if self.live_graph_lines is None:  # or use self.live_graph_ready
        if self.live_graph_ready == False:  # or use self.live_graph_ready
            self.live_graph_lines, = a_ax.plot(
                [], [], 'o', label=self.name
            )  # note unpack comma -- seem to be a list of 1 element
            #            msg    =  f"self.live_graph_lines created for device: {self.name} {type(self.live_graph_lines)}  {self.live_graph_lines}"
            #            AppGlobal.logger.info( msg )
            #            print( msg )

            #           got  >>>> why a list   self.live_graph_lines: <class 'list'>  [<matplotlib.lines.Line2D object at 0x00000274E0287AC8>]
            self.linestyle, self.colorstyle, self.markerstyle, self.widthstyle = AppGlobal.graph_live.line_style.get_next_style(
            )
            self.live_graph_ready = True
Пример #2
0
    def check_timer_done(self, ):
        """
        for now do not assume timer is running
        call from ht polling action
        """
        msg = "SmartPlugAdapter.check_timer_done  "
        AppGlobal.log_if_wrong_thread(threading.get_ident(),
                                      msg=msg,
                                      main=False)

        if not (self.timer_on):
            return

        now = time.time()
        sec_left = (self.timer_start +
                    self.time_sec) - now  # could be timer_end stored
        #        print( f"check_timer_done sec_left {sec_left} for plug: {self.name} " )   # debug
        if sec_left <= 0:
            self.off()
            self.display_msg("Timer Stop")
        else:
            self.timer_sec_left = sec_left
            a_string = self.sec_to_string(sec_left)
            # just update display
            self.display_msg(f"Timer  {a_string}")
Пример #3
0
    def update_graph_live(self, ):
        """
        call from main thread

        from graph_live but could we use our own polling  ??
        return True or False, depending on weather we were already set up

        """
        msg = "SmartPlugAdapter.update_graph_live  "
        AppGlobal.log_if_wrong_thread(threading.get_ident(),
                                      msg=msg,
                                      main=True)

        #        msg    =  f"Adapter.update_graph_live device: {self.name}  data: {self.graphing_new_data} ready: {self.live_graph_ready}"
        #        AppGlobal.logger.info( msg )

        if (not self.graphing_new_data) or (not self.live_graph_ready):
            return False

        self.live_graph_lines.set_xdata(self.gd_time_adj)
        self.live_graph_lines.set_ydata(self.gd_power)

        # not sure these need to be done on every cycle but works
        self.live_graph_lines.set_linestyle(self.linestyle)
        self.live_graph_lines.set_color(self.colorstyle)
        self.live_graph_lines.set_marker(self.markerstyle)
        self.live_graph_lines.set_linewidth(self.widthstyle)
        self.live_graph_lines.set_label(
            self.name
        )  # not currently working lacks update or.... setting legend later seemed to do it once may be enough
        self.graphing_new_data = False

        return True
Пример #4
0
    def check_recording(self, ):
        """
        call helper thread, best or ok in main -- used by smart_plug not smart_plug_graphing
        if recording then record the data in db
        for now do not assume timer is running
        call from ht polling action
        """
        msg = "SmartPlugAdapter.check_recording  "
        AppGlobal.log_if_wrong_thread(threading.get_ident(),
                                      msg=msg,
                                      main=False)

        if not (self.recording or self.monitor):
            return

#        msg    =  f"?ht? adapter check_recording "
#        AppGlobal.what_thread( threading.get_ident(), msg, 20  )

        now = time.time()
        if now < self.next_record_time:  # or monitor time
            return

        self.last_record_time = now
        self.next_record_time = now + self.delta_t
        try:
            plug = pyHS100.SmartPlug(self.tcpip)
            plug_data = plug.get_emeter_realtime()

            # ?? could add plug state - on off,.....

            # id          = f"{self.name}{self.last_record_time}r"
            # print   ( f"record data {id}:{plug_data})" )
            rnd = "%.2f" % plug_data["power"]
            msg = f'{rnd} watts'  #!! bit of rounding would be nice here
            self.gui_tk_label_2.config(text=msg)

        except pyHS100.smartdevice.SmartDeviceException as exception:  # look up correct exception
            self.timer_on = False
            #self.record_off()  to much messaging and will throw own error
            msg = f"failed to communicate with plug - record off for: {self.name} {self.tcpip}"

            AppGlobal.gui.print_info_string(msg)
            return

        if AppGlobal.graph_live_flag and self.monitor and self.live_graph_ready:
            #            print( "check_recording" )
            self.graphing_new_data = True
            #!! normalized and unnormalize data
            self.gd_time.append(self.last_record_time)
            self.gd_time_adj.append(
                AppGlobal.graph_live.rescale_time_function(
                    self.last_record_time))  #?? make local ref??
            self.gd_power.append(plug_data["power"])

        if self.recording:
            db_data = ((self.name, self.last_record_time, "r", "?",
                        plug_data["voltage"], plug_data["current"],
                        plug_data["power"], plug_data["total"]), )
            self.insert_measurements(db_data)
Пример #5
0
 def polling_mt(self, ):
     """
     polling for the main thread ( gui thread )
     """
     msg = "SmartPlugAdapter.polling_mt  "
     AppGlobal.log_if_wrong_thread(threading.get_ident(),
                                   msg=msg,
                                   main=True)
Пример #6
0
 def polling_ht(self, ):
     """
     polling for the helper thread
     not sure this is ever needed
     """
     msg = "GraphLive.polling_ht  "
     AppGlobal.log_if_wrong_thread(threading.get_ident(),
                                   msg=msg,
                                   main=False)
Пример #7
0
    def polling(self):
        """
        started from gui thread as beginning of new thread
        this is an infinite loop monitoring the queue
        actions based on queue_to_helper and run_event
        application purpose is the device polling where we monitor/record the devices

        """
        #self.logger.debug(  "HealperThread.polling()  entered " )
        msg = "smart plug Helper.polling()"
        AppGlobal.log_if_wrong_thread(threading.get_ident(),
                                      msg=msg,
                                      main=False)

        while True:

            try:
                #                if self.last_time  + 10 < time.time():
                #                    self.last_time = time.time()
                #                    self.print_info_string(   "Time" + str( self.last_time  ) ) # + a_port )

                (action, function, function_args) = self.rec_from_queue()
                if action != "":
                    self.logger.debug("smart_plug_helper.polling() queue: " +
                                      action + " " + str(function) + " " +
                                      str(function_args))  # ?? comment out
                if action == "call":
                    #print( "ht making call" )
                    sys.stdout.flush()
                    self.controller.helper_task_active = True
                    function(*function_args)
                    self.logger.debug(
                        "smart_plug_helper.polling() return running helper loop "
                    )  # ?? comment out
                    #self.print_helper_label( "return running helper loop " )
                    self.controller.helper_task_active = False  # do we maintain this, or move to helper -- looks like not used, app global better location
                if action == "stop":
                    # seems to be working fine
                    msg = "helper got stop in the queue -- end thread with return "
                    # AppGlobal.what_thread( threading.get_ident(), msg, 50  )
                    self.controller.helper_task_active = False
                    return  # this will kill the thread --- think it is the return which should end the loop ?  or do we need a break -- we seem to keep looping
                    msg = "helper got stop in the queue -- ran thru return "
                    # AppGlobal.what_thread( threading.get_ident(), msg, 50  )

                self.device_polling()

            # must catch all exceptions if we do not want polling to stop ... but maybe we do
            except Exception as he:
                #self.logger.info( "schedule_me_helper.HelperThread threw exception from " + he.msg )        # info debug... !! also info to msg area
                msg = f"smart_plug_helper.HelperThread threw exception: {he}"
                print(f"see log: {msg}")
                self.logger.error(msg, exc_info=True)  # info debug...
            time.sleep(
                self.ht_delta_t)  # ok here since it is the main pooling loop
            #self.logger.debug(  "HealperThread.polling() done with sleep " )
        return
Пример #8
0
    def polling_ht(self, ):
        """
        polling for the helper thread
        """
        msg = "SmartPlugAdapter.polling_ht  "
        AppGlobal.log_if_wrong_thread(threading.get_ident(),
                                      msg=msg,
                                      main=False)

        self.check_timer_done()
        self.check_recording()
Пример #9
0
    def reset_graphing_data(self, ):
        """
        fine in helper thread ok in both
        """
        AppGlobal.log_if_wrong_thread(
            threading.get_ident(),
            msg="now in smart_plug_adapter.reset_graphing_data",
            main=True)
        #        print( "reset_graphing_data" )

        self.gd_time = []
        self.gd_time_adj = []
        self.gd_power = []
        #self.gd_power_adj        = []
        self.gd_energy = []
        self.gd_energy_adj = []

        self.graphing_new_data = False
Пример #10
0
    def run(self):
        """
        called when thread is started from gt its call should be considered as from ht
        """
        self.parameters.init_from_helper()

        self.scheduled_event_list = AppGlobal.scheduled_event_list
        id = threading.get_ident()

        msg = f"helper run  "
        AppGlobal.log_if_wrong_thread(threading.get_ident(),
                                      msg=msg,
                                      main=False)

        self.logger.debug(msg)

        #        print( "==============================================" )
        self.polling()  # may mach name in gui thread
Пример #11
0
    def graph_power_from_db(self, line_style=None, ax=None):
        """
        None default because required hence exception
        """
        msg = "SmartPlugAdapter.graph_power_from_db  "
        AppGlobal.log_if_wrong_thread(threading.get_ident(),
                                      msg=msg,
                                      main=True)

        line_style.get_next_style()
        time_data = self.gd_time_adj
        if ((time_data is None) or len(time_data) == 0):
            print(f"no data for {self.name}")
            return
        ax.plot(time_data,
                self.gd_power,
                linestyle=line_style.linestyle,
                marker=line_style.markerstyle,
                color=line_style.colorstyle,
                label=self.name)  # label= "Power (Watts)"
Пример #12
0
    def device_polling(self):
        """
        helper thread
        poll the devices - now just smartplugs, but fairly easily adapted to other polling
        tasks.
        so simple may put back in polling
        also extended for graphing
        """
        #        print( "device_polling" )
        msg = "HealperThread.device_polling  "
        AppGlobal.log_if_wrong_thread(threading.get_ident(),
                                      msg=msg,
                                      main=False)

        # AppGlobal.what_thread( threading.get_ident(), msg, 50  )
        now = time.time()
        for i_adapter in AppGlobal.smartplug_adapter_list:
            i_adapter.polling_ht()

        # now the live graph
#        print( f"AppGlobal.graph_live {AppGlobal.graph_live_flag}")
        if not AppGlobal.graph_live_flag:
            return
#        print( "smart_plug_helper device_polling graph_live" )
# think this test now in graph_live
        update_graph_bool = False
        for i_adapter in AppGlobal.smartplug_adapter_list:
            if i_adapter.graphing_new_data:
                update_graph_bool = True
                break
#        print( f"update_graph_bool {update_graph_bool}" )
        if not update_graph_bool:
            #            print( f"update_graph_bool {update_graph_bool}" )
            return
        AppGlobal.logger.error(
            "SmartPlugHelper.device_polling off to graph live")
        AppGlobal.graph_live.polling_ht()
Пример #13
0
    def polling_mt(self, ):
        """
        polling for the main thread ( gui thread )
        """
        msg = "GraphLive.polling_mt  "
        AppGlobal.log_if_wrong_thread(threading.get_ident(),
                                      msg=msg,
                                      main=True)
        #        AppGlobal.logger.error( msg )

        # collect flags from the individual devices
        need_redraw_flag = False
        for i_adapter in AppGlobal.smartplug_adapter_list:
            if i_adapter.update_graph_live():
                need_redraw_flag = True

        #AppGlobal.logger.error( "GraphLive.polling_mt test next" )
        if need_redraw_flag:
            AppGlobal.logger.error("GraphLive.polling_mt need redraw True")
            self.ax.relim()
            self.ax.autoscale_view()
            #We need to draw *and* flush
            AppGlobal.logger.error("GraphLive.polling_mt next draw flush")
            self.figure.canvas.draw()
            self.figure.canvas.flush_events()
            plt.legend(loc=2)  # help with update  -- seems to work
            #            AppGlobal.logger.error( "GraphLive.polling_mt polling show next" )
            plt.show(block=False)
            #            AppGlobal.logger.error( "GraphLive.polling_mtpolling post next" )

            # ------------ for tracking memory use
            self.debug_count += 1
            if self.debug_count > 50:
                AppGlobal.show_process_memory(
                    "GraphLive.polling_mt polling time to log", log_level=20)
                self.debug_count = 0
Пример #14
0
    def start_graph_live(self, ):
        """
        call from main thread
        start off a session of live graphing -- need to run in main thread
        moved from the plug
        no validation if start is ok
        no inactivation of controls .... even this should perhaps come from a checkbox


        what do we want to do:
            graph only plugs that are being monitored or recorded
            accumulate the data in a list ( list of tuples might be better than two lists or even a numpy type thing )

            ??? what is monitor, record is turned off ( keep data and graph line so far stop adding to data )
            ??? what if new adapter is turned on ( was it on earlire ?? )
            ??? export csv    export all cached data to a csv, if none just a message
        """
        msg = "GraphLive.start_graph_live"
        #        AppGlobal.what_thread( threading.get_ident(), msg, 20  )
        AppGlobal.log_if_wrong_thread(threading.get_ident(),
                                      msg=msg,
                                      main=True)

        self.rescale_time_function = lambda x: x  # default identity function
        self.set_rescale_time_function()

        #Set up plot
        self.figure, self.ax = plt.subplots(
            figsize=(self.parameters.graph_x_size,
                     self.parameters.graph_y_size))

        self.figure.canvas.mpl_connect('close_event', self.end_graph_live_evt)

        plt.legend(
            loc=2
        )  # for label to show up ?  # made small sq show up no content, too early ?
        # lets try to build the line in each adapter
        self.lines, = self.ax.plot(
            [], [], 'o', color="red", linewidth=2.5, linestyle="-"
        )  # the line is the thing to update ... can we add later, lets assume we can
        #Auto scale on unknown axis and known limits on the other
        self.ax.set_autoscaley_on(True)
        #self.ax.set_xlim(self.min_x, self.max_x)
        #Other stuff
        self.ax.grid(linestyle='-', linewidth='0.5', color='red')
        self.ax.tick_params(axis='y', labelcolor='red')

        self.ax.set_title(f"Power measured by SmartPlugs")
        self.ax.set_xlabel(
            f"Time in {self.graph_time_units} from {self.graph_time_zero}"
        )  # these have been set multiple times
        self.ax.set_ylabel(
            f"Power in watts")  # these have been set multiple times

        for i_adapter in AppGlobal.smartplug_adapter_list:
            i_adapter.start_graph_live(
                self.ax
            )  # this is a setup it does not start graphing by itself
        plt.show(block=False)
        AppGlobal.logger.error("GraphLive.start_graph_live complete")
        AppGlobal.graph_live_flag = True  # this will kick off in polling set last