def setup_sensors(self): """Setup server sensors.""" self.script.log(2, "KATCPServer::setup_sensors()") self._device_status = Sensor.discrete("device-status", description="Status of entire system", params=self.DEVICE_STATUSES, default="ok") self.add_sensor(self._device_status) self._beam_name = Sensor.string("beam-name", description="name of configured beam", unit="", default="") self.add_sensor(self._beam_name) # setup host based sensors self._host_name = Sensor.string("host-name", description="hostname of this server", unit="", default="") self.add_sensor(self._host_name) self.script.log(2, "KATCPServer::setup_sensors lmc="+str(self.script.lmc)) (host, port) = self.script.lmc.split(":") self.setup_sensors_host (host, port) self.script.log(2, "KATCPServer::setup_sensors beams="+str(self.script.beam)) self.setup_sensors_beam (self.script.beam_name)
def setup_sensors(self): """ @brief Set up all sensors on the server @note This is an internal method and is invoked by the constructor of the base class. """ super(EddMasterController, self).setup_sensors() self._control_mode_sensor = Sensor.string( "control-mode", description="The control mode for the EDD", default=self._control_mode, initial_status=Sensor.NOMINAL) self.add_sensor(self._control_mode_sensor) self._edd_config_sensor = Sensor.string( "current-config", description="The current configuration for the EDD backend", default="", initial_status=Sensor.UNKNOWN) self.add_sensor(self._edd_config_sensor) self._edd_scpi_interface_addr_sensor = Sensor.string( "scpi-interface-addr", description="The SCPI interface address for this instance", default="{}:{}".format(self._scpi_ip, self._scpi_port), initial_status=Sensor.NOMINAL) self.add_sensor(self._edd_scpi_interface_addr_sensor)
def setup_sensors(self): """ @brief Setup monitoring sensors """ self._device_status_sensor = Sensor.discrete( "device-status", description="Health status of FIServer", params=self.DEVICE_STATUSES, default="ok", initial_status=Sensor.UNKNOWN) self.add_sensor(self._device_status_sensor) self._active_beams_sensor = Sensor.float( "nbeams", description="Number of beams that are currently active", default=1, initial_status=Sensor.UNKNOWN) self.add_sensor(self._active_beams_sensor) self._nchannels_sensor = Sensor.float( "nchannels", description="Number of channels in each beam", default=1, initial_status=Sensor.UNKNOWN) self.add_sensor(self._nchannels_sensor) self._integration_time_sensor = Sensor.float( "integration-time", description="The integration time for each beam", default=1, initial_status=Sensor.UNKNOWN) self.add_sensor(self._integration_time_sensor) self._nblank_phases_sensor = Sensor.integer( "nblank-phases", description="The number of blank phases", default=1, initial_status=Sensor.UNKNOWN) self.add_sensor(self._nblank_phases_sensor)
def add_input_stream_sensor(self, streamid): """ @brief add sensors for i/o buffers for an input stream with given streamid. """ self._polarization_sensors[streamid] = {} self._polarization_sensors[streamid]["mkrecv_sensors"] = MkrecvSensors(streamid) for s in self._polarization_sensors[streamid]["mkrecv_sensors"].sensors.values(): self.add_sensor(s) self._polarization_sensors[streamid]["input-buffer-fill-level"] = Sensor.float( "input-buffer-fill-level-{}".format(streamid), description="Fill level of the input buffer for polarization{}".format(streamid), params=[0, 1]) self.add_sensor(self._polarization_sensors[streamid]["input-buffer-fill-level"]) self._polarization_sensors[streamid]["input-buffer-total-write"] = Sensor.float( "input-buffer-total-write-{}".format(streamid), description="Total write into input buffer for polarization {}".format(streamid), params=[0, 1]) self.add_sensor(self._polarization_sensors[streamid]["input-buffer-total-write"]) self._polarization_sensors[streamid]["output-buffer-fill-level"] = Sensor.float( "output-buffer-fill-level-{}".format(streamid), description="Fill level of the output buffer for polarization {}".format(streamid) ) self._polarization_sensors[streamid]["output-buffer-total-read"] = Sensor.float( "output-buffer-total-read-{}".format(streamid), description="Total read from output buffer for polarization {}".format(streamid) ) self.add_sensor(self._polarization_sensors[streamid]["output-buffer-total-read"]) self.add_sensor(self._polarization_sensors[streamid]["output-buffer-fill-level"])
def __init__(self, name_suffix, nsum=100): """ List of sensors and handler to be connected to a mkrecv process """ self.sensors = {} self.sensors['global_payload_frac'] = Sensor.float( "global-payload-received-fraction-{}".format(name_suffix), description="Ratio of received and expected payload.", params=[0, 1]) self.sensors['received_heaps_frac'] = Sensor.float( "received-heaps-frac-{}".format(name_suffix), description="Fraction of received heaps for last {} slots.".format( 100), params=[0, 1]) self.sensors['slot_received_heaps'] = Sensor.integer( "slot_received-heaps-{}".format(name_suffix), description="Received heaps.", ) self.sensors['slot_expected_heaps'] = Sensor.integer( "slot_expected-heaps-{}".format(name_suffix), description="Expected heaps.", ) self.sensors['missing_heaps'] = Sensor.string( "missing-heaps-{}".format(name_suffix), description="Missing heaps per multicast group.", ) self.__received_heaps = 0. self.__expected_heaps = 0. self.__idx = 0 self.__nsum = nsum self.__missing_heaps = np.zeros(8)
def setup_sensors(self): """ @brief Set up monitoring sensors. @note The following sensors are made available on top of default sensors implemented in AsynDeviceServer and its base classes. """ self._device_status_sensor = Sensor.discrete( "device-status", description="Health status of ApsWorkerServer instance", params=self.DEVICE_STATUSES, default="ok", initial_status=Sensor.NOMINAL) self.add_sensor(self._device_status_sensor) self._capture_interface_sensor = Sensor.string( "capture-interface", description="The IP address of the NIC to be used for data capture", default=self._capture_interface, initial_status=Sensor.NOMINAL) self.add_sensor(self._capture_interface_sensor) self._state_sensor = LoggingSensor.discrete( "state", params=self.STATES, description="The current state of this worker instance", default=self.IDLE, initial_status=Sensor.NOMINAL) self._state_sensor.set_logger(log) self.add_sensor(self._state_sensor)
def setup_sensors(self): """ @brief Set up monitoring sensors. @note The following sensors are made available on top of defaul sensors implemented in AsynDeviceServer and its base classes. device-status: Reports the health status of the FBFUSE and associated devices: Among other things report HW failure, SW failure and observation failure. """ self._device_status = Sensor.discrete( "device-status", description="Health status of BLUSE", params=self.DEVICE_STATUSES, default="ok", initial_status=Sensor.NOMINAL) self.add_sensor(self._device_status) self._local_time_synced = Sensor.boolean( "local-time-synced", description="Indicates BLUSE is NTP syncronised.", default=True, # TODO: implement actual NTP synchronization request initial_status=Sensor.NOMINAL) self.add_sensor(self._local_time_synced) self._version = Sensor.string( "version", description="Reports the current BLUSE version", default=str(self.VERSION_INFO[1:]).strip('()').replace( ' ', '').replace(",", '.'), # e.g. '1.0' initial_status=Sensor.NOMINAL) self.add_sensor(self._version)
def setup_sensors(self): """Set up basic monitoring sensors. """ for name, params in self._parser.items(): if params["type"] == "float": sensor = Sensor.float(name, description=params["description"], unit=params.get("units", None), default=params.get("default", 0.0), initial_status=Sensor.UNKNOWN) elif params["type"] == "string": sensor = Sensor.string(name, description=params["description"], default=params.get("default", ""), initial_status=Sensor.UNKNOWN) elif params["type"] == "int": sensor = Sensor.integer(name, description=params["description"], default=params.get("default", 0), unit=params.get("units", None), initial_status=Sensor.UNKNOWN) elif params["type"] == "bool": sensor = Sensor.boolean(name, description=params["description"], default=params.get("default", False), initial_status=Sensor.UNKNOWN) else: raise Exception("Unknown sensor type '{0}' requested".format( params["type"])) self.add_sensor(sensor)
def setup_sensors(self): sensor = Sensor(int, "sensor1", "Test sensor 1", "count", [0, 10]) sensor.set_value(sensor.value(), status=Sensor.UNKNOWN, timestamp=1) self.add_sensor(sensor) sensor2 = Sensor(int, "sensor2", "Test sensor 2", "count", [0, 10]) sensor2.set_value(sensor.value(), status=Sensor.UNKNOWN, timestamp=0) self.add_sensor(sensor2)
def setup_sensors(self): """ Setup monitoring sensors. The EDDPipeline base provides default sensors. Should be called by every subclass to ensure default sensors are available. """ self._pipeline_sensor_status = Sensor.discrete( "pipeline-status", description="Status of the pipeline", params=self.PIPELINE_STATES, default="idle", initial_status=Sensor.UNKNOWN) self.add_sensor(self._pipeline_sensor_status) self._edd_config_sensor = Sensor.string( "current-config", description="The current configuration for the EDD backend", default=json.dumps(self._config, indent=4), initial_status=Sensor.UNKNOWN) self.add_sensor(self._edd_config_sensor) self._log_level = Sensor.string("log-level", description="Log level", default=logging.getLevelName( log.level), initial_status=Sensor.NOMINAL) self.add_sensor(self._log_level)
def setup_sensors_beam (self, beam): b = str(beam) self._beam_sensors = {} self.script.log(2, "KATCPServer::setup_sensors_beam ="+b) self._beam_sensors["observing"] = Sensor.boolean("observing", description="Beam " + b + " is observing", unit="", default=0) self.add_sensor(self._beam_sensors["observing"]) self._beam_sensors["snr"] = Sensor.float("snr", description="SNR of Beam "+b, unit="", params=[0,1e9], default=0) self.add_sensor(self._beam_sensors["snr"]) self._beam_sensors["power"] = Sensor.float("power", description="Power Level of Beam "+b, unit="", default=0) self.add_sensor(self._beam_sensors["power"]) self._beam_sensors["integrated"] = Sensor.float("integrated", description="Length of integration for Beam "+b, unit="", default=0) self.add_sensor(self._beam_sensors["integrated"])
def __init__(self, name, description, units, stype, device, proxy, *formatted_params): self.basename = name self.device = device stype = Sensor.parse_type(stype) params = Sensor.parse_params(stype, formatted_params) Sensor.__init__(self, stype, device.name + '.' + name, description, units, params=params)
def periodic_plot_snapshot(self): log.debug("Start periodic plot") passthrough = ["rxs.packetizer.systemstatus.snapshot.totalpwr.h", "rxs.packetizer.systemstatus.snapshot.totalpwr.v", "rxs.packetizer.1pps.length", "rxs.packetizer.1pps.last", "s-band.center-frequency", "s-band.bandwidth", "s-band.noise-diode", "s-band.sampling-rate", "s-band.time.synchronisation-epoch", "rxs.packetizer.1pps.length", "rxs.packetizer.40g.selected-filter", "rxs.packetizer.device-status"] self.__pass_through_sensors = {} if not self.has_sensor(passthrough[0]): # Checking first is enough log.debug("Adding pass-through sensors") yield self._client._client.until_synced() log.debug("Client synced through sensors") sensor_list = yield self._client._client.list_sensors() for st in sensor_list: if st.name not in passthrough: log.debug(" - ignoring {}".format(st[1])) continue log.debug(" - adding {}".format(st)) try: if st.type == "discrete": t = "string" else: t = st.type s = Sensor(Sensor.parse_type(t), st.name, st.description, st.units) self.__pass_through_sensors[st.name] = st.object except Exception as E: log.exception(E) self.add_sensor(s) else: log.debug("pass through sensors already added") log.debug("Starting periodic plot") with ProcessPoolExecutor(max_workers=1) as executor: try: while self.__plotting: for key in passthrough: sensor = self.get_sensor(key) v = yield self.__pass_through_sensors[key].get_reading() sensor.set_value(v.value, timestamp=v.timestamp) starttime = time.time() data = yield self._client.get_snapshot() plt = yield executor.submit(plot_script, data) log.debug("Setting bandpass sensor with timestamp %", v.timestamp) self._bandpass.set_value(plt[0]) self._level.set_value(plt[1]) duration = time.time() - starttime log.debug("Plot duration: {} s".format(duration)) if duration > self._config['snapshot_frequency']: log.warning("Plot duration {} larger than plot interval!".format(duration, self._config["nplot"])) else: yield sleep(self._config['snapshot_frequency'] - duration) except Exception as E: log.error("Error in periodic plot. Abandon plotting.") log.exception(E)
def setup_sensors(self): sensor = Sensor(int, "sensor1", "Test sensor 1", "count", [0,10]) sensor._timestamp = 1 self.add_sensor(sensor) sensor2 = Sensor(int, "sensor2", "Test sensor 2", "count", [0, 10]) sensor2._timestamp = 0 self.add_sensor(sensor2)
def setup_sensors(self): """ @brief Set up monitoring sensors. @note The following sensors are made available on top of default sensors implemented in AsynDeviceServer and its base classes. device-status: Reports the health status of the controller and associated devices: Among other things report HW failure, SW failure and observation failure. local-time-synced: Indicates whether the local time of the servers is synchronised to the master time reference (use NTP). This sensor is aggregated from all nodes that are part of FBF and will return "not sync'd" if any nodes are unsyncronised. products: The list of product_ids that controller is currently handling """ self._device_status = Sensor.discrete( "device-status", description="Health status of FBFUSE", params=self.DEVICE_STATUSES, default="ok", initial_status=Sensor.NOMINAL) self.add_sensor(self._device_status) self._local_time_synced = Sensor.boolean( "local-time-synced", description="Indicates FBF is NTP syncronised.", default=True, initial_status=Sensor.UNKNOWN) self.add_sensor(self._local_time_synced) def ntp_callback(): log.debug("Checking NTP sync") try: synced = check_ntp_sync() except Exception: log.exception("Unable to check NTP sync") self._local_time_synced.set_value(False) else: if not synced: log.warning("Server is not NTP synced") self._local_time_synced.set_value(synced) ntp_callback() self._ntp_callback = PeriodicCallback(ntp_callback, NTP_CALLBACK_PERIOD) self._ntp_callback.start() self._products_sensor = Sensor.string( "products", description="The names of the currently configured products", default="", initial_status=Sensor.NOMINAL) self.add_sensor(self._products_sensor)
def setup_sensors(self): """ @brief Set up monitoring sensors. Sensor list: - device-status - local-time-synced - fbf0-status - fbf1-status @note The following sensors are made available on top of default sensors implemented in AsynDeviceServer and its base classes. device-status: Reports the health status of the FBFUSE and associated devices: Among other things report HW failure, SW failure and observation failure. """ self._device_status_sensor = Sensor.discrete( "device-status", description = "Health status of FbfWorkerServer instance", params = self.DEVICE_STATUSES, default = "ok", initial_status = Sensor.NOMINAL) self.add_sensor(self._device_status_sensor) self._state_sensor = LoggingSensor.discrete( "state", params = self.STATES, description = "The current state of this worker instance", default = self.IDLE, initial_status = Sensor.NOMINAL) self._state_sensor.set_logger(log) self.add_sensor(self._state_sensor) self._delay_client_sensor = Sensor.string( "delay-engine-server", description = "The address of the currently set delay engine", default = "", initial_status = Sensor.UNKNOWN) self.add_sensor(self._delay_client_sensor) self._antenna_capture_order_sensor = Sensor.string( "antenna-capture-order", description = "The order in which the worker will capture antennas internally", default = "", initial_status = Sensor.UNKNOWN) self.add_sensor(self._antenna_capture_order_sensor) self._mkrecv_header_sensor = Sensor.string( "mkrecv-header", description = "The MKRECV/DADA header used for configuring capture with MKRECV", default = "", initial_status = Sensor.UNKNOWN) self.add_sensor(self._mkrecv_header_sensor)
def __init__(self,polling_interval=1): super(CpuMonitor,self).__init__(polling_interval) for cpu_idx in range(psutil.cpu_count()): self._sensors["cpu%02d_percent"%cpu_idx] = Sensor.float("cpu%02d_percent"%cpu_idx, description = "percentage usage of cpu%02d"%cpu_idx, params = [0,200], unit = "%", default = 0) self._sensors["cpu%02d_temperature"%cpu_idx] = Sensor.float("cpu%02d_temperature"%cpu_idx, description = "temperature of cpu%02d"%cpu_idx, params = [0,200], unit = "Celsius", default = 0)
def setup_sensors(self): """Setup server sensors.""" self.script.log(2, "KATCPServer::setup_sensors()") self._device_status = Sensor.discrete( "device-status", description="Status of entire system", params=self.DEVICE_STATUSES, default="ok") self.add_sensor(self._device_status) self._beam_name = Sensor.string("beam-name", description="name of configured beam", unit="", default="") self.add_sensor(self._beam_name) # setup host based sensors self._host_name = Sensor.string("host-name", description="hostname of this server", unit="", default="") self.add_sensor(self._host_name) # GUI URL TODO remove hardcoding guis = [{ "title": "PTUSE Web Interface", "description": "Live Pulsar timing monitoring plots", "href": self.script.cfg["SPIP_ADDRESS"] }] encoded = json.dumps(guis) self._gui_urls = Sensor.string("gui-urls", description="PTUSE GUI URL", unit="", default=encoded) self.add_sensor(self._gui_urls) self._gui_urls.set_value(encoded) # give LMC some time to prepare the socket time.sleep(5) self.script.log( 1, "KATCPServer::setup_sensors lmc=" + str(self.script.lmc)) (host, port) = self.script.lmc.split(":") self.setup_sensors_host(host, port) self.script.log( 2, "KATCPServer::setup_sensors beams=" + str(self.script.beam)) self.setup_sensors_beam(self.script.beam_name)
def setup_sensors(self): super(PafMasterController, self).setup_sensors() self._paf_config_sensor = Sensor.string( "current-config", description="The currently set configuration for the PAF backend", default="", initial_status=Sensor.UNKNOWN) self.add_sensor(self._paf_config_sensor) self._status_server_sensor = Sensor.address( "status-server-address", description="The address of the status server", default="", initial_status=Sensor.UNKNOWN) self.add_sensor(self._status_server_sensor)
def __init__(self,polling_interval=1): super(MemoryMonitor,self).__init__(polling_interval) for node in get_meminfo().keys(): name_ = "%s_memory_size"%node self._sensors[name_] = Sensor.float(name_, description = "total memory on %s"%node, params = [8192,1e9], unit = "MB", default = 0) name_ = "%s_memory_avail"%node self._sensors[name_] = Sensor.float(name_, description = "available memory on %s"%node, params = [8192,1e9], unit = "MB", default = 0)
def setup_sensors(self): """Setup some server sensors.""" self._time_result = Sensor(Sensor.TIMESTAMP, "time.result", "Last ?time result.", "") self._read_result = Sensor(Sensor.STRING, "read.result", "Last ?read result.", "") self._write_result = Sensor(Sensor.STRING, "write.result", "Last ?write result.", "") self.add_sensor(self._time_result) self.add_sensor(self._read_result) self.add_sensor(self._write_result)
def setup_sensors(self): """ @brief Setup the default KATCP sensors. @note As this call is made only upon an PAF configure call a mass inform is required to let connected clients know that the proxy interface has changed. """ self._state_sensor = LoggingSensor.discrete( "state", description="Denotes the state of this PAF instance", params=self.STATES, default=self.IDLE, initial_status=Sensor.NOMINAL) self._state_sensor.set_logger(self.log) self.add_sensor(self._state_sensor) self._servers_sensor = Sensor.string( "servers", description= "The worker server instances currently allocated to this product", default=",".join([ "{s.hostname}:{s.port}".format(s=server) for server in self._servers ]), initial_status=Sensor.UNKNOWN) self.add_sensor(self._servers_sensor) self._parent.mass_inform(Message.inform('interface-changed')) self._state_sensor.set_value(self.IDLE)
def request_target_configuration_start(self, req, product_id, target_string): """ @brief Set up a beam configuration sensor for the FBFUSE instance @param product_id The product identifier @param target_string A KATPOINT target string (boresight pointing position) """ log.info( "Received target configuration request for '{}' with target: {}". format(product_id, target_string)) if not product_id in self._configuration_sensors: log.debug( "Creating configuration sensor for '{}'".format(product_id)) self._configuration_sensors[product_id] = Sensor.string( "{}-beam-position-configuration".format(product_id), description="Configuration description for FBF beam placement", default="", initial_status=Sensor.UNKNOWN) self.add_sensor(self._configuration_sensors[product_id]) self.mass_inform(Message.inform('interface-changed')) initial_config = yield self.get_target_config(product_id, target_string) self.update_target_config(product_id, initial_config) raise Return(("ok", ))
def __init__(self,volumes,polling_interval=1): super(DiskMonitor,self).__init__(polling_interval) self._volumes = volumes for name,path in self._volumes: name_ = "%s_partition_size"%name self._sensors[name_] = Sensor.float(name_, description = "total size of %s partition"%name, params = [8192,1e9], unit = "MB", default = 0) name_ = "%s_partition_avail"%name self._sensors[name_] = Sensor.float(name_, description = "available space on %s partition"%name, params = [8192,1e9], unit = "MB", default = 0)
def setup_sensors(self): """ @brief Setup monitoring sensors """ self._beam_sensor0 = Sensor.float("beam0.id", description="The ID of current beam", default=0, initial_status=Sensor.UNKNOWN) self.sensors.append(self._beam_sensor0) self._instant_sensor0 = Sensor.float( "beam0.inst-packet-loss-fraction", description="The instanteous packet loss fraction", default=0, initial_status=Sensor.UNKNOWN) self.sensors.append(self._instant_sensor0) self._time_sensor0 = Sensor.float( "beam0.time-elapsed", description="The time so far in seconds", default=0, initial_status=Sensor.UNKNOWN) self.sensors.append(self._time_sensor0) self._average_sensor0 = Sensor.float( "beam0.total-packet-loss-fraction", description="Fraction of packets lost", default=0, initial_status=Sensor.UNKNOWN) self.sensors.append(self._average_sensor0) self._beam_sensor1 = Sensor.float("beam1.id", description="The ID of current beam", default=0, initial_status=Sensor.UNKNOWN) self.sensors.append(self._beam_sensor1) self._instant_sensor1 = Sensor.float( "beam1.inst-packet-loss-fraction", description="The instanteous packet loss fraction", default=0, initial_status=Sensor.UNKNOWN) self.sensors.append(self._instant_sensor1) self._time_sensor1 = Sensor.float( "beam1.time-elapsed", description="The time so far in seconds", default=0, initial_status=Sensor.UNKNOWN) self.sensors.append(self._time_sensor1) self._average_sensor1 = Sensor.float( "beam1.total-packet-loss-fraction", description="Fraction of packets lost", default=0, initial_status=Sensor.UNKNOWN) self.sensors.append(self._average_sensor1)
def test_differential_timestamp(self): # Test that the timetamp differential is stored correctly as # seconds. This is mainly to check the conversion of the katcp spec from # milliseconds to seconds for katcp v5 spec. time_diff = 4.12 # Time differential in seconds ts_sensor = Sensor(Sensor.TIMESTAMP, 'ts', 'ts sensor', '') diff = sampling.SampleDifferential(self.inform, ts_sensor, time_diff) self.assertEqual(diff._threshold, time_diff)
def add_input_stream_sensor(self, streamid): """ Add sensors for i/o buffers for an input stream with given streamid. """ self._polarization_sensors[streamid] = {} self._polarization_sensors[streamid]["mkrecv_sensors"] = MkrecvSensors( streamid) for s in self._polarization_sensors[streamid][ "mkrecv_sensors"].sensors.values(): self.add_sensor(s) self._polarization_sensors[streamid][ "input-buffer-fill-level"] = Sensor.float( "input-buffer-fill-level-{}".format(streamid), description="Fill level of the input buffer for polarization{}" .format(streamid), initial_status=Sensor.UNKNOWN, params=[0, 1]) self.add_sensor( self._polarization_sensors[streamid]["input-buffer-fill-level"]) self._polarization_sensors[streamid][ "input-buffer-total-write"] = Sensor.float( "input-buffer-total-write-{}".format(streamid), description="Total write into input buffer for polarization {}" .format(streamid), initial_status=Sensor.UNKNOWN, params=[0, 1]) self.add_sensor( self._polarization_sensors[streamid]["input-buffer-total-write"]) self._polarization_sensors[streamid][ "output-buffer-fill-level"] = Sensor.float( "output-buffer-fill-level-{}".format(streamid), description="Fill level of the output buffer for polarization {}" .format(streamid), initial_status=Sensor.UNKNOWN) self._polarization_sensors[streamid][ "output-buffer-total-read"] = Sensor.float( "output-buffer-total-read-{}".format(streamid), description="Total read from output buffer for polarization {}" .format(streamid), initial_status=Sensor.UNKNOWN) self.add_sensor( self._polarization_sensors[streamid]["output-buffer-total-read"]) self.add_sensor( self._polarization_sensors[streamid]["output-buffer-fill-level"]) self.mass_inform(Message.inform('interface-changed'))
def add_sensors(self, sensor_infos): """Add fake sensors sensor_infos is a dict <sensor-name> : ( <description>, <unit>, <sensor-type>, <params>*) The sensor info is string-reprs of whatever they are, as they would be on the wire in a real KATCP connection. Values are passed to a katcp.Message object, so some automatic conversions are done, hence it is OK to pass numbers without stringifying them. """ # Check sensor validity. parse_type() and parse_params should raise if not OK for s_name, s_info in sensor_infos.items(): s_type = Sensor.parse_type(s_info[2]) s_params = Sensor.parse_params(s_type, s_info[3:]) self.fake_sensor_infos.update(sensor_infos) self._fic._interface_changed.set()
def setup_sensors(self): """ @brief Setup monitoring sensors """ EDDPipeline.setup_sensors(self) self._bandpass = Sensor.string( "bandpass_PNG", description="band-pass data (base64 encoded)", initial_status=Sensor.UNKNOWN) self.add_sensor(self._bandpass) self._level = Sensor.string( "level_PNG", description="ADC Level (base64 encoded)", initial_status=Sensor.UNKNOWN) self.add_sensor(self._level)
def request_add_sensor(self, msg): self.factory.add_sensor( Sensor(int, 'int_sensor%d' % len(self.factory.sensors), 'descr', 'unit', params=[-10, 10])) return Message.reply('add-sensor', 'ok')
def setup_sensors(self): """ @brief Set up monitoring sensors. """ self._target_sensors = [] for beam in self._beam_manager.get_beams(): sensor = Sensor.string("{}-target".format(beam.idx), description="Target for beam {}".format( beam.idx), default=beam.target.format_katcp(), initial_status=Sensor.UNKNOWN) self.add_sensor(sensor) beam.register_observer(lambda beam, sensor=sensor: sensor. set_value(beam.target.format_katcp())) antenna_map = { a.name: a.format_katcp() for a in self._beam_manager.antennas } self._antennas_sensor = Sensor.string( "antennas", description= "JSON breakdown of the antennas (in KATPOINT format) associated with this delay engine", default=json.dumps(antenna_map), initial_status=Sensor.NOMINAL) self.add_sensor(self._antennas_sensor) self._phase_reference_sensor = Sensor.string( "phase-reference", description= "A KATPOINT target string denoting the F-engine phasing centre", default="unset,radec,0,0", initial_status=Sensor.UNKNOWN) self.add_sensor(self._phase_reference_sensor) reference_antenna = Antenna( "reference,{ref.lat},{ref.lon},{ref.elev}".format( ref=self._beam_manager.antennas[0].ref_observer)) self._reference_antenna_sensor = Sensor.string( "reference-antenna", description= "A KATPOINT antenna string denoting the reference antenna", default=reference_antenna.format_katcp(), initial_status=Sensor.NOMINAL) self.add_sensor(self._reference_antenna_sensor)
def setup_sensors(self): self._device_status = Sensor.discrete( "device-status", description="Health status of PafBackendController", params=self.DEVICE_STATUSES, default="ok", initial_status=Sensor.UNKNOWN) self.add_sensor(self._device_status)
def setup_sensors(self): """Setup server sensors.""" self.script.log(2, "KATCPServer::setup_sensors()") self._device_status = Sensor.discrete("device-status", description="Status of entire system", params=self.DEVICE_STATUSES, default="ok") self.add_sensor(self._device_status) self._beam_name = Sensor.string("beam-name", description="name of configured beam", unit="", default="") self.add_sensor(self._beam_name) # setup host based sensors self._host_name = Sensor.string("host-name", description="hostname of this server", unit="", default="") self.add_sensor(self._host_name) # GUI URL TODO remove hardcoding guis = [ { "title": "PTUSE Web Interface", "description": "Live Pulsar timing monitoring plots", "href": self.script.cfg["SPIP_ADDRESS"] } ] encoded = json.dumps(guis) self._gui_urls = Sensor.string("gui-urls", description="PTUSE GUI URL", unit="", default=encoded) self.add_sensor(self._gui_urls) self._gui_urls.set_value(encoded) # give LMC some time to prepare the socket time.sleep(5) self.script.log(1, "KATCPServer::setup_sensors lmc="+str(self.script.lmc)) (host, port) = self.script.lmc.split(":") self.setup_sensors_host (host, port) self.script.log(2, "KATCPServer::setup_sensors beams="+str(self.script.beam)) self.setup_sensors_beam (self.script.beam_name)
def setup_sensors(self): """Setup some server sensors.""" self._add_result = Sensor.float("add.result", "Last ?add result.", "", [-10000, 10000]) self._add_result.set_value(0, Sensor.UNREACHABLE) self._time_result = Sensor.timestamp("time.result", "Last ?time result.", "") self._time_result.set_value(0, Sensor.INACTIVE) self._eval_result = Sensor.string("eval.result", "Last ?eval result.", "") self._eval_result.set_value('', Sensor.UNKNOWN) self._fruit_result = Sensor.discrete("fruit.result", "Last ?pick-fruit result.", "", self.FRUIT) self._fruit_result.set_value('apple', Sensor.ERROR) self.add_sensor(self._add_result) self.add_sensor(self._time_result) self.add_sensor(self._eval_result) self.add_sensor(self._fruit_result)
def setup_sensors(self): """Setup some server sensors.""" self._add_result = Sensor.float("add.result", "Last ?add result.", "", [-10000, 10000]) self._time_result = Sensor.timestamp("time.result", "Last ?time result.", "") self._eval_result = Sensor.string("eval.result", "Last ?eval result.", "") self._fruit_result = Sensor.discrete("fruit.result", "Last ?pick-fruit result.", "", self.FRUIT) self._james_result = Sensor.string("james.result", "Last ?james result.", "") self.add_sensor(self._add_result) self.add_sensor(self._time_result) self.add_sensor(self._eval_result) self.add_sensor(self._fruit_result) self.add_sensor(self._james_result)
def setup_sensors(self): """Setup some server sensors.""" self._add_result = Sensor(Sensor.FLOAT, "add.result", "Last ?add result.", "", [-10000, 10000]) self._time_result = Sensor(Sensor.TIMESTAMP, "time.result", "Last ?time result.", "") self._eval_result = Sensor(Sensor.STRING, "eval.result", "Last ?eval result.", "") self._fruit_result = Sensor(Sensor.DISCRETE, "fruit.result", "Last ?pick-fruit result.", "", self.FRUIT) self._band_result = Sensor(Sensor.DISCRETE, "band.result", "Last ?pick-band result.", "", self.BAND) self.add_sensor(self._add_result) self.add_sensor(self._time_result) self.add_sensor(self._eval_result) self.add_sensor(self._fruit_result) self.add_sensor(self._band_result)
def setup_sensors_beam (self, beam): b = str(beam) self._beam_sensors = {} self.script.log(2, "KATCPServer::setup_sensors_beam beam="+b) self._beam_sensors["observing"] = Sensor.boolean("observing", description="Beam " + b + " is observing", unit="", default=0) self.add_sensor(self._beam_sensors["observing"]) self._beam_sensors["snr"] = Sensor.float("snr", description="SNR of Beam "+b, unit="", params=[0,1e9], default=0) self.add_sensor(self._beam_sensors["snr"]) self._beam_sensors["beamformer_stddev_polh"] = Sensor.float("beamformer_stddev_polh", description="Standard deviation of beam voltages for pol H", unit="", params=[0,127], default=0) self.add_sensor(self._beam_sensors["beamformer_stddev_polh"]) self._beam_sensors["beamformer_stddev_polv"] = Sensor.float("beamformer_stddev_polv", description="Standard deviation of beam voltages for pol V", unit="", params=[0,127], default=0) self.add_sensor(self._beam_sensors["beamformer_stddev_polv"]) self._beam_sensors["integrated"] = Sensor.float("integrated", description="Length of integration for Beam "+b, unit="", default=0) self.add_sensor(self._beam_sensors["integrated"]) self._beam_sensors["input_channels"] = Sensor.integer("input_channels", description="Number of configured input channels for Beam "+b, unit="", default=0) self.add_sensor(self._beam_sensors["input_channels"])
def __init__(self, sensor_description, sensor_manager): """Subclasses must arrange to call this in their __init__(). Parameters ---------- sensor_description : dict Description of the KATCP sensor, with keys same as the parameters of :class:`katcp.Sensor` sensor_manager : :class:`KATCPSensorsManager` instance Manages sensor strategies, allows sensor polling, and provides time """ self._manager = sensor_manager self.clear_listeners() self._reading = KATCPSensorReading(0, 0, Sensor.UNKNOWN, None) # We'll be abusing a katcp.Sensor object slightly to make use of its # parsing and formatting functionality self._sensor = Sensor(**sensor_description) self._name = self._sensor.name # Overide the katpc.Sensor's set method with ours self._sensor.set = self.set # Steal the the katcp.Sensor's set_formatted method. Since we overrode # its set() method with ours, calling set_formatted will result in this # KATCPSensor object's value being set. self.set_formatted = self._sensor.set_formatted
class KATCPSensor(object): """Wrapper around a specific KATCP sensor on a given KATCP device. Each available KATCP sensor for a particular device has an associated :class:`KATCPSensor` object in the object hierarchy. This wrapper is mainly for interactive convenience. It provides the KATCP request help string as a docstring and registers listeners. Subclasses need to call the base class version of __init__(). """ __metaclass__ = abc.ABCMeta def __init__(self, sensor_description, sensor_manager): """Subclasses must arrange to call this in their __init__(). Parameters ---------- sensor_description : dict Description of the KATCP sensor, with keys same as the parameters of :class:`katcp.Sensor` sensor_manager : :class:`KATCPSensorsManager` instance Manages sensor strategies, allows sensor polling, and provides time """ self._manager = sensor_manager self.clear_listeners() self._reading = KATCPSensorReading(0, 0, Sensor.UNKNOWN, None) # We'll be abusing a katcp.Sensor object slightly to make use of its # parsing and formatting functionality self._sensor = Sensor(**sensor_description) self._name = self._sensor.name # Overide the katpc.Sensor's set method with ours self._sensor.set = self.set # Steal the the katcp.Sensor's set_formatted method. Since we overrode # its set() method with ours, calling set_formatted will result in this # KATCPSensor object's value being set. self.set_formatted = self._sensor.set_formatted @property def parent_name(self): """Name of the parent of this KATCPSensor""" return self._manager.resource_name @property def name(self): """Name of this KATCPSensor""" return self._name @property def normalised_name(self): """Normalised name of this KATCPSensor that can be used as a python identifier""" return escape_name(self._name) @property def reading(self): """Most recently received sensor reading as KATCPSensorReading instance""" return self._reading @property def value(self): return self._reading.value @property def status(self): return self._reading.status @property def sampling_strategy(self): """Current sampling strategy""" return self._manager.get_sampling_strategy(self.name) @property def description(self): return self._sensor.description @property def units(self): return self._sensor.units @property def type(self): return self._sensor.type def parse_value(self, s_value): """Parse a value from a string. Parameters ---------- s_value : str A string value to attempt to convert to a value for the sensor. Returns ------- value : object A value of a type appropriate to the sensor. """ return self._sensor.parse_value(s_value) def set_strategy(self, strategy, params=None): """Set current sampling strategy for sensor. Add this footprint for backwards compatibility. Parameters ---------- strategy : seq of str or str As tuple contains (<strat_name>, [<strat_parm1>, ...]) where the strategy names and parameters are as defined by the KATCP spec. As str contains the same elements in space-separated form. params : seq of str or str (<strat_name>, [<strat_parm1>, ...]) Returns ------- done : tornado Future that resolves when done or raises KATCPSensorError """ if not params: param_args = [] elif isinstance(params, basestring): param_args = [str(p) for p in params.split(' ')] else: if not isinstance(params, collections.Iterable): params = (params,) param_args = [str(p) for p in params] samp_strategy = " ".join([strategy] + param_args) return self._manager.set_sampling_strategy(self.name, samp_strategy) def set_sampling_strategy(self, strategy): """Set current sampling strategy for sensor Parameters ---------- strategy : seq of str or str As tuple contains (<strat_name>, [<strat_parm1>, ...]) where the strategy names and parameters are as defined by the KATCP spec. As str contains the same elements in space-separated form. Returns ------- done : tornado Future that resolves when done or raises KATCPSensorError """ return self._manager.set_sampling_strategy(self.name, strategy) def register_listener(self, listener, reading=False): """Add a callback function that is called when sensor value is updated. The callback footprint is received_timestamp, timestamp, status, value. Parameters ---------- listener : function Callback signature: if reading listener(katcp_sensor, reading) where `katcp_sensor` is this KATCPSensor instance `reading` is an instance of :class:`KATCPSensorReading` Callback signature: default, if not reading listener(received_timestamp, timestamp, status, value) """ listener_id = hashable_identity(listener) self._listeners[listener_id] = (listener, reading) logger.debug( 'Register listener for {}' .format(self.name)) def unregister_listener(self, listener): """Remove a listener callback added with register_listener(). Parameters ---------- listener : function Reference to the callback function that should be removed """ listener_id = hashable_identity(listener) self._listeners.pop(listener_id, None) def is_listener(self, listener): listener_id = hashable_identity(listener) return listener_id in self._listeners def clear_listeners(self): """Clear any registered listeners to updates from this sensor.""" self._listeners = {} def call_listeners(self, reading): logger.debug( 'Calling listeners {}' .format(self.name)) for listener, use_reading in self._listeners.values(): try: if use_reading: listener(self, reading) else: listener(reading.received_timestamp, reading.timestamp, reading.status, reading.value) except Exception: logger.exception( 'Unhandled exception calling KATCPSensor callback {0!r}' .format(listener)) def set(self, timestamp, status, value): """Set sensor with a given received value, matches :meth:`katcp.Sensor.set`""" received_timestamp = self._manager.time() reading = KATCPSensorReading(received_timestamp, timestamp, status, value) self._reading = reading self.call_listeners(reading) def set_value(self, value, status=Sensor.NOMINAL, timestamp=None): """Set sensor value with optinal specification of status and timestamp""" if timestamp is None: timestamp = self._manager.time() self.set(timestamp, status, value) def set_formatted(self, raw_timestamp, raw_status, raw_value, major): """Set sensor using KATCP string formatted inputs Mirrors :meth:`katcp.Sensor.set_formatted`. This implementation is empty. Will, during instantiation, be overridden by the set_formatted() method of a katcp.Sensor object. """ @tornado.gen.coroutine def get_reading(self): """Get a fresh sensor reading from the KATCP resource Returns ------- reply : tornado Future resolving with :class:`KATCPSensorReading` object Note ---- As a side-effect this will update the reading stored in this object, and result in registered listeners being called. """ yield self._manager.poll_sensor(self._name) # By now the sensor manager should have set the reading raise Return(self._reading) @tornado.gen.coroutine def get_value(self): """Get a fresh sensor value from the KATCP resource Returns ------- reply : tornado Future resolving with :class:`KATCPSensorReading` object Note ---- As a side-effect this will update the reading stored in this object, and result in registered listeners being called. """ yield self._manager.poll_sensor(self._name) # By now the sensor manager should have set the reading raise Return(self._reading.value) @tornado.gen.coroutine def get_status(self): """Get a fresh sensor status from the KATCP resource Returns ------- reply : tornado Future resolving with :class:`KATCPSensorReading` object Note ---- As a side-effect this will update the reading stored in this object, and result in registered listeners being called. """ yield self._manager.poll_sensor(self._name) # By now the sensor manager should have set the reading raise Return(self._reading.status) def wait(self, condition_or_value, timeout=None): """Wait for the sensor to satisfy a condition. Parameters ---------- condition_or_value : obj or callable, or seq of objs or callables If obj, sensor.value is compared with obj. If callable, condition_or_value(reading) is called, and must return True if its condition is satisfied. Since the reading is passed in, the value, status, timestamp or received_timestamp attributes can all be used in the check. TODO: Sequences of conditions (use SensorTransitionWaiter thingum?) timeout : float or None The timeout in seconds (None means wait forever) Returns ------- This command returns a tornado Future that resolves with True when the sensor value satisfies the condition. It will never resolve with False; if a timeout is given a TimeoutError happens instead. Raises ------ :class:`KATCPSensorError` If the sensor does not have a strategy set :class:`tornado.gen.TimeoutError` If the sensor condition still fails after a stated timeout period """ if (isinstance(condition_or_value, collections.Sequence) and not isinstance(condition_or_value, basestring)): raise NotImplementedError( 'Currently only single conditions are supported') condition_test = (condition_or_value if callable(condition_or_value) else lambda s: s.value == condition_or_value) ioloop = tornado.ioloop.IOLoop.current() f = Future() if self.sampling_strategy == ('none', ): raise KATCPSensorError( 'Cannot wait on a sensor that does not have a strategy set') def handle_update(sensor, reading): # This handler is called whenever a sensor update is received try: assert sensor is self if condition_test(reading): self.unregister_listener(handle_update) # Try and be idempotent if called multiple times after the # condition is matched. This should not happen unless the # sensor object is being updated in a thread outside of the # ioloop. if not f.done(): ioloop.add_callback(f.set_result, True) except Exception: f.set_exc_info(sys.exc_info()) self.unregister_listener(handle_update) self.register_listener(handle_update, reading=True) # Handle case where sensor is already at the desired value ioloop.add_callback(handle_update, self, self._reading) if timeout: to = ioloop.time() + timeout timeout_f = with_timeout(to, f) # Make sure we stop listening if the wait times out to prevent a # buildup of listeners timeout_f.add_done_callback( lambda f: self.unregister_listener(handle_update)) return timeout_f else: return f
class MyServer(DeviceServer): VERSION_INFO = ("dummy-server", 1, 0) BUILD_INFO = ("hipsr-dummy-server", 0, 1, "") def setup_sensors(self): """Setup some server sensors.""" self._time_result = Sensor(Sensor.TIMESTAMP, "time.result", "Last ?time result.", "") self._read_result = Sensor(Sensor.STRING, "read.result", "Last ?read result.", "") self._write_result = Sensor(Sensor.STRING, "write.result", "Last ?write result.", "") self.add_sensor(self._time_result) self.add_sensor(self._read_result) self.add_sensor(self._write_result) @request() @return_reply(Timestamp()) def request_time(self, sock): """Return the current time in ms since the Unix Epoch.""" r = time.time() self._time_result.set_value(r) return ("ok", r) @request(Str(),Int(),Int()) @return_reply(Str()) def request_read(self, sock, device_name, bytes, offset=0): """Dummy implementation of kactp ?read command Opens a pickled data file stored in /snap directory, and returns a packed struct of the data. Notes ----- * The pickle should already be packed as a struct. * Currently ignoring the bytes and offset arguments. """ # Attempt to load pickled data try: filename='%s/registers/%s.pkl'%(os.getcwd(),device_name) data = pkl.load(open(filename,'r')) except: return ("fail", "Could not load %s."%filename) # Return data self._read_result.set_value(data) return ("ok", data) @request(Str(),Int(),Str()) @return_reply(Str()) def request_write(self, sock, device_name, offset, data): """Dummy implementation of kactp ?write command Opens a pickled data file stored in /register directory, and writes a value to it. Notes ----- * katcp_wrapper passes us already serialzed data, so no need to use struct """ # Attempt to dump pickled data try: filename='%s/registers/%s.pkl'%(os.getcwd(),device_name) pkl.dump(data, open(filename,'w')) except: return ("fail", "Could not dump %s."%filename) return ("ok", data)
def setup_sensors(instrument, katcp_server): """ Set up compound sensors to be reported to CAM :param katcp_server: the katcp server with which to register the sensors :return: """ nr_engines = len(instrument.fhosts + instrument.xhosts) executor = futures.ThreadPoolExecutor(max_workers=nr_engines) if not instrument._initialised: raise RuntimeError('Cannot set up sensors until instrument is initialised.') ioloop = getattr(instrument, 'ioloop', None) if not ioloop: ioloop = getattr(katcp_server, 'ioloop', None) if not ioloop: raise RuntimeError('IOLoop-containing katcp version required. Can go no further.') instrument._sensors = {} # f-engine lru for _f in instrument.fhosts: sensor = Sensor.boolean(name='%s_feng_lru' % _f.host, description='F-engine %s LRU okay' % _f.host, default=True) katcp_server.add_sensor(sensor) instrument._sensors[sensor.name] = sensor ioloop.add_callback(_sensor_cb_flru, sensor, executor, _f) # x-engine lru for _x in instrument.xhosts: sensor = Sensor.boolean(name='%s_xeng_lru' % _x.host, description='X-engine %s LRU okay' % _x.host, default=True) katcp_server.add_sensor(sensor) instrument._sensors[sensor.name] = sensor ioloop.add_callback(_sensor_cb_xlru, sensor, executor, _x) # f-engine tx counters for _f in instrument.fhosts: sensor = Sensor.boolean(name='%s_feng_tx' % _f.host, description='F-engine TX okay - counters incrementing', default=True) katcp_server.add_sensor(sensor) instrument._sensors[sensor.name] = sensor ioloop.add_callback(_sensor_feng_tx, sensor, executor, _f) # f-engine rx counters for _f in instrument.fhosts: sensor = Sensor.boolean(name='%s_feng_rx' % _f.host, description='F-engine RX okay - counters incrementing', default=True) katcp_server.add_sensor(sensor) instrument._sensors[sensor.name] = sensor ioloop.add_callback(_sensor_feng_rx, sensor, executor, _f) # x-engine tx counters for _x in instrument.xhosts: sensor = Sensor.boolean(name='%s_xeng_tx' % _x.host, description='X-engine TX okay - counters incrementing', default=True) katcp_server.add_sensor(sensor) instrument._sensors[sensor.name] = sensor ioloop.add_callback(_sensor_xeng_tx, sensor, executor, _x) # x-engine rx counters for _x in instrument.xhosts: sensor = Sensor.boolean(name='%s_xeng_rx' % _x.host, description='X-engine RX okay - counters incrementing', default=True) katcp_server.add_sensor(sensor) instrument._sensors[sensor.name] = sensor ioloop.add_callback(_sensor_xeng_rx, sensor, executor, _x) # x-engine QDR errors for _x in instrument.xhosts: sensor = Sensor.boolean(name='%s_xeng_qdr' % _x.host, description='X-engine QDR okay', default=True) katcp_server.add_sensor(sensor) instrument._sensors[sensor.name] = sensor ioloop.add_callback(_xeng_qdr_okay, sensor, executor, _x) # f-engine QDR errors for _f in instrument.fhosts: sensor = Sensor.boolean(name='%s_feng_qdr' % _f.host, description='F-engine QDR okay', default=True) katcp_server.add_sensor(sensor) instrument._sensors[sensor.name] = sensor ioloop.add_callback(_feng_qdr_okay, sensor, executor, _f) # x-engine PHY counters for _x in instrument.xhosts: sensor = Sensor.boolean(name='%s_xeng_phy' % _x.host, description='X-engine PHY okay', default=True) katcp_server.add_sensor(sensor) instrument._sensors[sensor.name] = sensor ioloop.add_callback(_sensor_xeng_phy, sensor, executor, _x) # f-engine PHY counters for _f in instrument.fhosts: sensor = Sensor.boolean(name='%s_feng_phy' % _f.host, description='F-engine PHY okay', default=True) katcp_server.add_sensor(sensor) instrument._sensors[sensor.name] = sensor ioloop.add_callback(_sensor_feng_phy, sensor, executor, _f) # f-engine PFB counters for _f in instrument.fhosts: sensor = Sensor.boolean(name='%s_feng_pfb' % _f.host, description='F-engine PFB okay', default=True) katcp_server.add_sensor(sensor) instrument._sensors[sensor.name] = sensor ioloop.add_callback(_feng_pfb_okay, sensor, executor, _f) # f-engine comms rx fengops = instrument.fops sensor = Sensor.boolean(name='fhosts_check_rx', description='F-hosts rx okay', default=True) katcp_server.add_sensor(sensor) instrument._sensors[sensor.name] = sensor ioloop.add_callback(_fhost_check_rx, sensor, executor, fengops) # # f-engine comms tx sensor = Sensor.boolean(name='fhosts_check_tx', description='F-hosts tx okay', default=True) katcp_server.add_sensor(sensor) instrument._sensors[sensor.name] = sensor ioloop.add_callback(_fhost_check_tx, sensor, executor, fengops) # x-engine comms rx xengops = instrument.xops sensor = Sensor.boolean(name='xhosts_check_rx', description='X-hosts rx okay', default=True) katcp_server.add_sensor(sensor) instrument._sensors[sensor.name] = sensor ioloop.add_callback(_xhost_check_rx, sensor, executor, xengops)
def setup_sensors(self): self.add_sensor(Sensor.boolean('asens'))
def setup_sensors_host (self, host, port): self.script.log(1, "KATCPServer::setup_sensors_host ("+host+","+port+")") sock = sockets.openSocket (DL, host, int(port), 1) if sock: self.script.log(2, "KATCPServer::setup_sensors_host sock.send(" + self.script.lmc_cmd + ")") sock.send (self.script.lmc_cmd + "\r\n") lmc_reply = sock.recv (65536) sock.close() xml = xmltodict.parse(lmc_reply) self.script.log(2, "KATCPServer::setup_sensors_host sock.recv=" + str(xml)) self._host_sensors = {} # Disk sensors self.script.log(2, "KATCPServer::setup_sensors_host configuring disk sensors") disk_prefix = host+".disk" self._host_sensors["disk_size"] = Sensor.float(disk_prefix+".size", description=host+": disk size", unit="MB", params=[8192,1e9], default=0) self._host_sensors["disk_available"] = Sensor.float(disk_prefix+".available", description=host+": disk available space", unit="MB", params=[1024,1e9], default=0) self.add_sensor(self._host_sensors["disk_size"]) self.add_sensor(self._host_sensors["disk_available"]) # Server Load sensors self.script.log(2, "KATCPServer::setup_sensors_host configuring load sensors") self._host_sensors["num_cores"] = Sensor.integer (host+".num_cores", description=host+": disk available space", unit="MB", params=[1,64], default=0) self._host_sensors["load1"] = Sensor.float(host+".load.1min", description=host+": 1 minute load ", unit="", default=0) self._host_sensors["load5"] = Sensor.float(host+".load.5min", description=host+": 5 minute load ", unit="", default=0) self._host_sensors["load15"] = Sensor.float(host+".load.15min", description=host+": 15 minute load ", unit="", default=0) self._host_sensors["local_time_synced"] = Sensor.boolean("local_time_synced", description=host+": NTP server synchronisation", unit="", default=0) self.add_sensor(self._host_sensors["num_cores"]) self.add_sensor(self._host_sensors["num_cores"]) self.add_sensor(self._host_sensors["load1"]) self.add_sensor(self._host_sensors["load5"]) self.add_sensor(self._host_sensors["load15"]) self.add_sensor(self._host_sensors["local_time_synced"]) cpu_temp_pattern = re.compile("cpu[0-9]+_temp") fan_speed_pattern = re.compile("fan[0-9,a-z]+") power_supply_pattern = re.compile("ps[0-9]+_status") self.script.log(2, "KATCPServer::setup_sensors_host configuring other metrics") if not xml["lmc_reply"]["sensors"] == None: for sensor in xml["lmc_reply"]["sensors"]["metric"]: name = sensor["@name"] if name == "system_temp": self._host_sensors[name] = Sensor.float((host+".system_temp"), description=host+": system temperature", unit="C", params=[-20,150], default=0) self.add_sensor(self._host_sensors[name]) if cpu_temp_pattern.match(name): (cpu, junk) = name.split("_") self._host_sensors[name] = Sensor.float((host+"." + name), description=host+": "+ cpu +" temperature", unit="C", params=[-20,150], default=0) self.add_sensor(self._host_sensors[name]) if fan_speed_pattern.match(name): self._host_sensors[name] = Sensor.float((host+"." + name), description=host+": "+name+" speed", unit="RPM", params=[0,20000], default=0) self.add_sensor(self._host_sensors[name]) if power_supply_pattern.match(name): self._host_sensors[name] = Sensor.boolean((host+"." + name), description=host+": "+name, unit="", default=0) self.add_sensor(self._host_sensors[name]) # TODO consider adding power supply sensors: e.g. # device-status-kronos1-powersupply1 # device-status-kronos1-powersupply2 # device-status-kronos2-powersupply1 # device-status-kronos2-powersupply2 # TODO consider adding raid/disk sensors: e.g. # device-status-<host>-raid # device-status-<host>-raid-disk1 # device-status-<host>-raid-disk2 self.script.log(2, "KATCPServer::setup_sensors_host done!") else: self.script.log(2, "KATCPServer::setup_sensors_host no sensors found") else: self.script.log(-2, "KATCPServer::setup_sensors_host: could not connect to LMC")
class MyServer(DeviceServer): VERSION_INFO = ("dummy-server", 1, 0) BUILD_INFO = ("hipsr-dummy-server", 0, 1, "") FRUIT = [ "apple", "banana", "pear", "kiwi", ] BANDS = [ "autolux", "nirvana", "acdc", "tool", ] def setup_sensors(self): """Setup some server sensors.""" self._add_result = Sensor(Sensor.FLOAT, "add.result", "Last ?add result.", "", [-10000, 10000]) self._time_result = Sensor(Sensor.TIMESTAMP, "time.result", "Last ?time result.", "") self._eval_result = Sensor(Sensor.STRING, "eval.result", "Last ?eval result.", "") self._fruit_result = Sensor(Sensor.DISCRETE, "fruit.result", "Last ?pick-fruit result.", "", self.FRUIT) self._band_result = Sensor(Sensor.DISCRETE, "band.result", "Last ?pick-band result.", "", self.BAND) self.add_sensor(self._add_result) self.add_sensor(self._time_result) self.add_sensor(self._eval_result) self.add_sensor(self._fruit_result) self.add_sensor(self._band_result) @request(Float(), Float()) @return_reply(Float()) def request_add(self, sock, x, y): """Add two numbers""" r = x + y self._add_result.set_value(r) return ("ok", r) @request() @return_reply(Timestamp()) def request_time(self, sock): """Return the current time in ms since the Unix Epoch.""" r = time.time() self._time_result.set_value(r) return ("ok", r) @request(Str()) @return_reply(Str()) def request_eval(self, sock, expression): """Evaluate a Python expression.""" r = str(eval(expression)) self._eval_result.set_value(r) return ("ok", r) @request() @return_reply(Discrete(FRUIT)) def request_pick_fruit(self, sock): """Pick a random fruit.""" r = random.choice(self.FRUIT + [None]) if r is None: return ("fail", "No fruit.") self._fruit_result.set_value(r) return ("ok", r) @request() @return_reply(Discrete(BAND)) def request_pick_band(self, sock): """Pick a random fruit.""" r = random.choice(self.BAND + [None]) if r is None: return ("fail", "No band.") self._fruit_result.set_value(r) return ("ok", r)