def calculate_and_set_PWM(self):
        '''
        Uses the algorithm described in RainSensorHeaterAlgorithm.pdf to decide
        whether to use impulse heating mode, then determines the correct PWM
        value.
        '''
        self.logger.info('Calculating new PWM Value')
        # Get Last n minutes of rain history
        now = dt.utcnow()
        start = now - tdelta(0, int(self.heater_cfg['impulse_cycle']))
        db = PanMongo()
        entries = [x for x in db.weather.find({'date': {'$gt': start, '$lt': now}})
                   ]
        self.logger.info('  Found {} entries in last {:d} seconds.'.format(
                         len(entries), int(self.heater_cfg['impulse_cycle']),
                         ))
        last_entry = [x for x in db.current.find({"type": "weather"})
                      ][0]['data']
        rain_history = [x['data']['Rain Safe']
                        for x
                        in entries
                        if 'Rain Safe' in x['data'].keys()
                        ]

        if 'Ambient Temperature (C)' not in last_entry.keys():
            self.logger.warning('  Do not have Ambient Temperature measurement.  Can not determine PWM value.')
        elif 'Rain Sensor Temp (C)' not in last_entry.keys():
            self.logger.warning('  Do not have Rain Sensor Temperature measurement.  Can not determine PWM value.')
        else:
            # Decide whether to use the impulse heating mechanism
            if len(rain_history) > 3 and not np.any(rain_history):
                self.logger.info('  Consistent wet/rain in history.  Using impulse heating.')
                if self.impulse_heating:
                    impulse_time = (now - self.impulse_start).total_seconds()
                    if impulse_time > float(self.heater_cfg['impulse_duration']):
                        self.logger.info('  Impulse heating has been on for > {:.0f} seconds.  Turning off.'.format(
                                         float(self.heater_cfg['impulse_duration'])
                                         ))
                        self.impulse_heating = False
                        self.impulse_start = None
                    else:
                        self.logger.info('  Impulse heating has been on for {:.0f} seconds.'.format(
                                         impulse_time))
                else:
                    self.logger.info('  Starting impulse heating sequence.')
                    self.impulse_start = now
                    self.impulse_heating = True
            else:
                self.logger.info('  No impulse heating needed.')
                self.impulse_heating = False
                self.impulse_start = None

            # Set PWM Based on Impulse Method or Normal Method
            if self.impulse_heating:
                target_temp = float(last_entry['Ambient Temperature (C)']) + float(self.heater_cfg['impulse_temp'])
                if last_entry['Rain Sensor Temp (C)'] < target_temp:
                    self.logger.info('  Rain sensor temp < target.  Setting heater to 100 %.')
                    self.set_PWM(100)
                else:
                    new_PWM = AAG_heater_algorithm(target_temp, last_entry)
                    self.logger.info('  Rain sensor temp > target.  Setting heater to {:d} %.'.format(new_PWM))
                    self.set_PWM(new_PWM)
            else:
                if last_entry['Ambient Temperature (C)'] < self.heater_cfg['low_temp']:
                    deltaT = self.heater_cfg['low_delta']
                elif last_entry['Ambient Temperature (C)'] > self.heater_cfg['high_temp']:
                    deltaT = self.heater_cfg['high_delta']
                else:
                    frac = (last_entry['Ambient Temperature (C)'] - self.heater_cfg['low_temp']) /\
                           (self.heater_cfg['high_temp'] - self.heater_cfg['low_temp'])
                    deltaT = self.heater_cfg['low_delta'] + frac * \
                        (self.heater_cfg['high_delta'] - self.heater_cfg['low_delta'])
                target_temp = last_entry['Ambient Temperature (C)'] + deltaT
                new_PWM = int(self.heater_PID.recalculate(last_entry['Rain Sensor Temp (C)'],
                                                          new_set_point=target_temp))
                self.logger.debug('  last PID interval = {:.1f} s'.format(self.heater_PID.last_interval))
                self.logger.info('  target={:4.1f}, actual={:4.1f}, new PWM={:3.0f}, P={:+3.0f}, I={:+3.0f} ({:2d}), D={:+3.0f}'.format(
                    target_temp, last_entry['Rain Sensor Temp (C)'],
                    new_PWM, self.heater_PID.Kp * self.heater_PID.Pval,
                    self.heater_PID.Ki * self.heater_PID.Ival,
                    len(self.heater_PID.history),
                    self.heater_PID.Kd * self.heater_PID.Dval,
                ))
                self.set_PWM(new_PWM)
dataset/ETHPy150Open panoptes/POCS/scripts/read_weather.py/AAGCloudSensor.calculate_and_set_PWM/original