import math from ScEpTIC.emulator.energy import energy_utils from ScEpTIC.emulator.energy.mcu.options import MCUClockCycleAction, ADCPowerState from ScEpTIC.emulator.energy.options import OpModeName from ScEpTIC.emulator.energy.voltage_drawner import VoltageDrawner class SHT85(VoltageDrawner): """ Energy model of a SHT85 digital temperature humidity sensor https://sensirion.com/media/documents/4B40CEF3/640B2346/Sensirion_Humidity_Sensors_SHT85_Datasheet.pdf """ STATES = ['on', 'off'] CC_READ_COMMAND = 1 CC_READ_DATA = 2 datasheet = { 'V': 3.3, 'I_min': '600u', 'I_max': '1500u', } t_wakeup = '1.5m' t_read = '15.5m' def __init__(self): self.state = 'off' avg_i = (energy_utils.str_to_float(self.datasheet['I_min']) + energy_utils.str_to_float(self.datasheet['I_max'])) / 2.0 self.resistance = self.datasheet['V'] / avg_i self.system_model = None def attach_system_model(self, system_model): self.system_model = system_model def set_state(self, state): """ Set state (off, on) """ if state not in self.STATES: raise Exception('SHT85 - Invalid state') self.state = state def simulate_set_state(self, state): ticks = 0 # activate sensor ticks += self.system_model.run_step(MCUClockCycleAction.NO_MEMORY_ACCESS, OpModeName.SIMULATE_SENSOR) # enter LPM and wait for sensor to be on if state == 'on' and self.state == 'off': ticks += self.system_model.run_step(MCUClockCycleAction.LPM_ENTER, OpModeName.LPM_ENTER) lpm_start_time = self.system_model.get_simulation_time() wait_time = energy_utils.str_to_float(self.t_wakeup) lpm_end_time = lpm_start_time + wait_time while self.system_model.get_simulation_time() < lpm_end_time: ticks += self.system_model.run_step(MCUClockCycleAction.LPM_NOP, OpModeName.SIMULATE_SENSOR) ticks += self.system_model.run_step(MCUClockCycleAction.LPM_EXIT, OpModeName.LPM_EXIT) self.set_state(state) return ticks def simulate_read(self): # Activate the sensor ticks = self.simulate_set_state('on') self.system_model.enable_lpm_precise_ticks() # send read command for _ in range(self.CC_READ_COMMAND): ticks += self.system_model.run_step(MCUClockCycleAction.NO_MEMORY_ACCESS, OpModeName.SIMULATE_SENSOR) # enter LPM ticks += self.system_model.run_step(MCUClockCycleAction.LPM_ENTER, OpModeName.LPM_ENTER) lpm_start_time = self.system_model.get_simulation_time() wait_time = energy_utils.str_to_float(self.t_read) lpm_end_time = lpm_start_time + wait_time while self.system_model.get_simulation_time() < lpm_end_time: ticks += self.system_model.run_step(MCUClockCycleAction.LPM_NOP, OpModeName.SIMULATE_SENSOR) ticks += self.system_model.run_step(MCUClockCycleAction.LPM_EXIT, OpModeName.LPM_EXIT) # read data for _ in range(self.CC_READ_DATA): ticks += self.system_model.run_step(MCUClockCycleAction.NO_MEMORY_ACCESS, OpModeName.SIMULATE_SENSOR) # Deactivate the sensor ticks += self.simulate_set_state('off') self.system_model.disable_lpm_precise_ticks() return ticks def get_drained_energy(self, t): """ Calculates the energy consumed by the component. :param t: elapsed time :return: the consumed energy """ voltage = self.voltage_source.get_voltage() if self.state == 'off': return 0.0 energy_from_R = energy_utils.energy_from_R_t(voltage, self.resistance, t) return energy_from_R