From 17bdcac61be79b651f495336c90f3815774d5ab4 Mon Sep 17 00:00:00 2001 From: Robin Date: Tue, 20 Feb 2018 07:55:54 +0000 Subject: [PATCH] Adds filesize component (#12211) * Create filesize.py * Update filesize.py * Updates filesize Addresses issues raised in review * Update .coveragerc * Addresses requested changes Addresses the changes requested by @baloob. Additionally the file size in bytes is now available in attributes. * Create test_filesize.py This isn't working yet * Update test_filesize.py * Update test_filesize.py * Update test_filesize.py * Update test_filesize.py * Update test_filesize.py * Update test_filesize.py * fixed valid file test * Update test_filesize.py * Fix indentation Fix incorrect indentation in setup * Update filesize.py * Update filesize.py --- .coveragerc | 1 + homeassistant/components/sensor/filesize.py | 92 +++++++++++++++++++++ tests/components/sensor/test_filesize.py | 58 +++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 homeassistant/components/sensor/filesize.py create mode 100644 tests/components/sensor/test_filesize.py diff --git a/.coveragerc b/.coveragerc index 97be3406b37a46..34e9ddbd5d294a 100644 --- a/.coveragerc +++ b/.coveragerc @@ -558,6 +558,7 @@ omit = homeassistant/components/sensor/etherscan.py homeassistant/components/sensor/fastdotcom.py homeassistant/components/sensor/fedex.py + homeassistant/components/sensor/filesize.py homeassistant/components/sensor/fitbit.py homeassistant/components/sensor/fixer.py homeassistant/components/sensor/fritzbox_callmonitor.py diff --git a/homeassistant/components/sensor/filesize.py b/homeassistant/components/sensor/filesize.py new file mode 100644 index 00000000000000..a5a65f9bb5e120 --- /dev/null +++ b/homeassistant/components/sensor/filesize.py @@ -0,0 +1,92 @@ +""" +Sensor for monitoring the size of a file. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.filesize/ +""" +import datetime +import logging +import os + +import voluptuous as vol + +from homeassistant.helpers.entity import Entity +import homeassistant.helpers.config_validation as cv +from homeassistant.components.sensor import PLATFORM_SCHEMA + +_LOGGER = logging.getLogger(__name__) + + +CONF_FILE_PATHS = 'file_paths' +ICON = 'mdi:file' + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_FILE_PATHS): + vol.All(cv.ensure_list, [cv.isfile]), +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up the file size sensor.""" + sensors = [] + for path in config.get(CONF_FILE_PATHS): + if not hass.config.is_allowed_path(path): + _LOGGER.error( + "Filepath %s is not valid or allowed", path) + continue + else: + sensors.append(Filesize(path)) + + if sensors: + add_devices(sensors, True) + + +class Filesize(Entity): + """Encapsulates file size information.""" + + def __init__(self, path): + """Initialize the data object.""" + self._path = path # Need to check its a valid path + self._size = None + self._last_updated = None + self._name = path.split("/")[-1] + self._unit_of_measurement = 'MB' + + def update(self): + """Update the sensor.""" + statinfo = os.stat(self._path) + self._size = statinfo.st_size + last_updated = datetime.datetime.fromtimestamp(statinfo.st_mtime) + self._last_updated = last_updated.isoformat() + + @property + def name(self): + """Return the name of the sensor.""" + return self._name + + @property + def state(self): + """Return the size of the file in MB.""" + decimals = 2 + state_mb = round(self._size/1e6, decimals) + return state_mb + + @property + def icon(self): + """Icon to use in the frontend, if any.""" + return ICON + + @property + def device_state_attributes(self): + """Return other details about the sensor state.""" + attr = { + 'path': self._path, + 'last_updated': self._last_updated, + 'bytes': self._size, + } + return attr + + @property + def unit_of_measurement(self): + """Return the unit of measurement of this entity, if any.""" + return self._unit_of_measurement diff --git a/tests/components/sensor/test_filesize.py b/tests/components/sensor/test_filesize.py new file mode 100644 index 00000000000000..23ef1c6081b313 --- /dev/null +++ b/tests/components/sensor/test_filesize.py @@ -0,0 +1,58 @@ +"""The tests for the filesize sensor.""" +import unittest +import os + +from homeassistant.components.sensor.filesize import CONF_FILE_PATHS +from homeassistant.setup import setup_component +from tests.common import get_test_home_assistant + + +TEST_DIR = os.path.join(os.path.dirname(__file__)) +TEST_FILE = os.path.join(TEST_DIR, 'mock_file_test_filesize.txt') + + +def create_file(path): + """Create a test file.""" + with open(path, 'w') as test_file: + test_file.write("test") + + +class TestFileSensor(unittest.TestCase): + """Test the filesize sensor.""" + + def setup_method(self, method): + """Set up things to be run when tests are started.""" + self.hass = get_test_home_assistant() + self.hass.config.whitelist_external_dirs = set((TEST_DIR)) + + def teardown_method(self, method): + """Stop everything that was started.""" + if os.path.isfile(TEST_FILE): + os.remove(TEST_FILE) + self.hass.stop() + + def test_invalid_path(self): + """Test that an invalid path is caught.""" + config = { + 'sensor': { + 'platform': 'filesize', + CONF_FILE_PATHS: ['invalid_path']} + } + self.assertTrue( + setup_component(self.hass, 'sensor', config)) + assert len(self.hass.states.entity_ids()) == 0 + + def test_valid_path(self): + """Test for a valid path.""" + create_file(TEST_FILE) + config = { + 'sensor': { + 'platform': 'filesize', + CONF_FILE_PATHS: [TEST_FILE]} + } + self.assertTrue( + setup_component(self.hass, 'sensor', config)) + assert len(self.hass.states.entity_ids()) == 1 + state = self.hass.states.get('sensor.mock_file_test_filesizetxt') + assert state.state == '0.0' + assert state.attributes.get('bytes') == 4