mirror of
				https://github.com/KevinMidboe/python-gpiozero.git
				synced 2025-10-29 17:50:37 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			250 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			250 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # vim: set fileencoding=utf-8:
 | |
| 
 | |
| from __future__ import (
 | |
|     unicode_literals,
 | |
|     print_function,
 | |
|     absolute_import,
 | |
|     division,
 | |
| )
 | |
| str = type('')
 | |
| 
 | |
| 
 | |
| import os
 | |
| import io
 | |
| import subprocess
 | |
| from datetime import datetime, time
 | |
| 
 | |
| from .devices import Device
 | |
| from .mixins import EventsMixin
 | |
| 
 | |
| 
 | |
| class InternalDevice(EventsMixin, Device):
 | |
|     """
 | |
|     Extends :class:`Device` to provide a basis for devices which have no
 | |
|     specific hardware representation. These are effectively pseudo-devices and
 | |
|     usually represent operating system services like the internal clock, file
 | |
|     systems or network facilities.
 | |
|     """
 | |
| 
 | |
| 
 | |
| class PingServer(InternalDevice):
 | |
|     """
 | |
|     Extends :class:`InternalDevice` to provide a device which is active when a
 | |
|     *host* on the network can be pinged.
 | |
| 
 | |
|     The following example lights an LED while a server is reachable (note the
 | |
|     use of :attr:`~SourceMixin.source_delay` to ensure the server is not
 | |
|     flooded with pings)::
 | |
| 
 | |
|         from gpiozero import PingServer, LED
 | |
|         from signal import pause
 | |
| 
 | |
|         google = PingServer('google.com')
 | |
|         led = LED(4)
 | |
| 
 | |
|         led.source_delay = 60  # check once per minute
 | |
|         led.source = google.values
 | |
| 
 | |
|         pause()
 | |
| 
 | |
|     :param str host:
 | |
|         The hostname or IP address to attempt to ping.
 | |
|     """
 | |
|     def __init__(self, host):
 | |
|         self.host = host
 | |
|         super(PingServer, self).__init__()
 | |
|         self._fire_events()
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return '<gpiozero.PingServer host="%s">' % self.host
 | |
| 
 | |
|     @property
 | |
|     def value(self):
 | |
|         # XXX This is doing a DNS lookup every time it's queried; should we
 | |
|         # call gethostbyname in the constructor and ping that instead (good
 | |
|         # for consistency, but what if the user *expects* the host to change
 | |
|         # address?)
 | |
|         with io.open(os.devnull, 'wb') as devnull:
 | |
|             try:
 | |
|                 subprocess.check_call(
 | |
|                     ['ping', '-c1', self.host],
 | |
|                     stdout=devnull, stderr=devnull)
 | |
|             except subprocess.CalledProcessError:
 | |
|                 return False
 | |
|             else:
 | |
|                 return True
 | |
| 
 | |
| 
 | |
| class CPUTemperature(InternalDevice):
 | |
|     """
 | |
|     Extends :class:`InternalDevice` to provide a device which is active when
 | |
|     the CPU temperature exceeds the *threshold* value.
 | |
| 
 | |
|     The following example plots the CPU's temperature on an LED bar graph::
 | |
| 
 | |
|         from gpiozero import LEDBarGraph, CPUTemperature
 | |
|         from signal import pause
 | |
| 
 | |
|         # Use minimums and maximums that are closer to "normal" usage so the
 | |
|         # bar graph is a bit more "lively"
 | |
|         cpu = CPUTemperature(min_temp=50, max_temp=90)
 | |
| 
 | |
|         print('Initial temperature: {}C'.format(cpu.temperature))
 | |
| 
 | |
|         graph = LEDBarGraph(5, 6, 13, 19, 25, pwm=True)
 | |
|         graph.source = cpu.values
 | |
| 
 | |
|         pause()
 | |
| 
 | |
|     :param str sensor_file:
 | |
|         The file from which to read the temperature. This defaults to the
 | |
|         sysfs file :file:`/sys/class/thermal/thermal_zone0/temp`. Whatever
 | |
|         file is specified is expected to contain a single line containing the
 | |
|         temperature in milli-degrees celsius.
 | |
| 
 | |
|     :param float min_temp:
 | |
|         The temperature at which :attr:`value` will read 0.0. This defaults to
 | |
|         0.0.
 | |
| 
 | |
|     :param float max_temp:
 | |
|         The temperature at which :attr:`value` will read 1.0. This defaults to
 | |
|         100.0.
 | |
| 
 | |
|     :param float threshold:
 | |
|         The temperature above which the device will be considered "active".
 | |
|         This defaults to 80.0.
 | |
|     """
 | |
|     def __init__(self, sensor_file='/sys/class/thermal/thermal_zone0/temp',
 | |
|             min_temp=0.0, max_temp=100.0, threshold=80.0):
 | |
|         self.sensor_file = sensor_file
 | |
|         super(CPUTemperature, self).__init__()
 | |
|         self.min_temp = min_temp
 | |
|         self.max_temp = max_temp
 | |
|         self.threshold = threshold
 | |
|         self._fire_events()
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return '<gpiozero.CPUTemperature temperature=%.2f>' % self.temperature
 | |
| 
 | |
|     @property
 | |
|     def temperature(self):
 | |
|         """
 | |
|         Returns the current CPU temperature in degrees celsius.
 | |
|         """
 | |
|         with io.open(self.sensor_file, 'r') as f:
 | |
|             return float(f.readline().strip()) / 1000
 | |
| 
 | |
|     @property
 | |
|     def value(self):
 | |
|         """
 | |
|         Returns the current CPU temperature as a value between 0.0
 | |
|         (representing the *min_temp* value) and 1.0 (representing the
 | |
|         *max_temp* value). These default to 0.0 and 100.0 respectively, hence
 | |
|         :attr:`value` is :attr:`temperature` divided by 100 by default.
 | |
|         """
 | |
|         temp_range = self.max_temp - self.min_temp
 | |
|         return (self.temperature - self.min_temp) / temp_range
 | |
| 
 | |
|     @property
 | |
|     def is_active(self):
 | |
|         """
 | |
|         Returns ``True`` when the CPU :attr:`temperature` exceeds the
 | |
|         :attr:`threshold`.
 | |
|         """
 | |
|         return self.temperature > self.threshold
 | |
| 
 | |
| 
 | |
| class TimeOfDay(InternalDevice):
 | |
|     """
 | |
|     Extends :class:`InternalDevice` to provide a device which is active when
 | |
|     the computer's clock indicates that the current time is between
 | |
|     *start_time* and *end_time* (inclusive) which are :class:`~datetime.time`
 | |
|     instances.
 | |
| 
 | |
|     The following example turns on a lamp attached to an :class:`Energenie`
 | |
|     plug between 7 and 8 AM::
 | |
| 
 | |
|         from gpiozero import TimeOfDay, Energenie
 | |
|         from datetime import time
 | |
|         from signal import pause
 | |
| 
 | |
|         lamp = Energenie(0)
 | |
|         morning = TimeOfDay(time(7), time(8))
 | |
| 
 | |
|         lamp.source = morning.values
 | |
| 
 | |
|         pause()
 | |
| 
 | |
|     :param ~datetime.time start_time:
 | |
|         The time from which the device will be considered active.
 | |
| 
 | |
|     :param ~datetime.time end_time:
 | |
|         The time after which the device will be considered inactive.
 | |
| 
 | |
|     :param bool utc:
 | |
|         If ``True`` (the default), a naive UTC time will be used for the
 | |
|         comparison rather than a local time-zone reading.
 | |
|     """
 | |
|     def __init__(self, start_time, end_time, utc=True):
 | |
|         self._start_time = None
 | |
|         self._end_time = None
 | |
|         self._utc = True
 | |
|         super(TimeOfDay, self).__init__()
 | |
|         self.start_time = start_time
 | |
|         self.end_time = end_time
 | |
|         self.utc = utc
 | |
|         self._fire_events()
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return '<gpiozero.TimeOfDay active between %s and %s %s>' % (
 | |
|                 self.start_time, self.end_time, ('local', 'UTC')[self.utc])
 | |
| 
 | |
|     @property
 | |
|     def start_time(self):
 | |
|         """
 | |
|         The time of day after which the device will be considered active.
 | |
|         """
 | |
|         return self._start_time
 | |
| 
 | |
|     @start_time.setter
 | |
|     def start_time(self, value):
 | |
|         if isinstance(value, datetime):
 | |
|             value = value.time()
 | |
|         if not isinstance(value, time):
 | |
|             raise ValueError('start_time must be a datetime, or time instance')
 | |
|         self._start_time = value
 | |
| 
 | |
|     @property
 | |
|     def end_time(self):
 | |
|         """
 | |
|         The time of day after which the device will be considered inactive.
 | |
|         """
 | |
|         return self._end_time
 | |
| 
 | |
|     @end_time.setter
 | |
|     def end_time(self, value):
 | |
|         if isinstance(value, datetime):
 | |
|             value = value.time()
 | |
|         if not isinstance(value, time):
 | |
|             raise ValueError('end_time must be a datetime, or time instance')
 | |
|         self._end_time = value
 | |
| 
 | |
|     @property
 | |
|     def utc(self):
 | |
|         """
 | |
|         If ``True``, use a naive UTC time reading for comparison instead of a
 | |
|         local timezone reading.
 | |
|         """
 | |
|         return self._utc
 | |
| 
 | |
|     @utc.setter
 | |
|     def utc(self, value):
 | |
|         self._utc = bool(value)
 | |
| 
 | |
|     @property
 | |
|     def value(self):
 | |
|         if self.utc:
 | |
|             return self.start_time <= datetime.utcnow().time() <= self.end_time
 | |
|         else:
 | |
|             return self.start_time <= datetime.now().time() <= self.end_time
 |