diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..4dc215a --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,17 @@ +FROM python:3.7 + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + git \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +RUN python -m pip install --upgrade colorlog black pylint +RUN python -m pip install --upgrade git+git://github.com/home-assistant/home-assistant.git@dev +RUN cd && mkdir -p /config/custom_components + + +WORKDIR /workspace + +# Set the default shell to bash instead of sh +ENV SHELL /bin/bash \ No newline at end of file diff --git a/.devcontainer/README.md b/.devcontainer/README.md new file mode 100644 index 0000000..f52282a --- /dev/null +++ b/.devcontainer/README.md @@ -0,0 +1,53 @@ +# Devcontainer + +_The easiest way to contribute to and/or test this repository._ + +## Requirements + +- [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) +- [docker](https://docs.docker.com/install/) +- [VS Code](https://code.visualstudio.com/) +- [Remote - Containers (VSC Extention)](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) + +[More info about requirements and devcontainer in general](https://code.visualstudio.com/docs/remote/containers#_getting-started) + +## How to use Devcontainer for development/test + +1. Make sure your computer meets the requirements. +1. Fork this repository. +1. Clone the repository to your computer. +1. Open the repository using VS Code. + +When you open this repository with VSCode and your computer meets the requirements you are asked to "Reopen in Container", do that. + +![reopen](images/reopen.png) + +If you don't see this notification, open the command pallet (ctrl+shift+p) and select `Remote-Containers: Reopen Folder in Container`. + +_It will now build the devcontainer._ + +The container have some "tasks" to help you testing your changes. + +## Custom Tasks in this repository + +_Start "tasks" by opening the the command pallet (ctrl+shift+p) and select `Tasks: Run Task`_ + +Running tasks like `Start Home Assistant on port 8124` can be restarted by opening the the command pallet (ctrl+shift+p) and select `Tasks: Restart Running Task`, then select the task you want to restart. + +### Start Home Assistant on port 8124 + +This will copy the configuration and the integration files to the expected location in the container. + +And start up Home Assistant on [port 8124.](http://localhost:8124) + +### Upgrade Home Assistant to latest dev + +This will upgrade Home Assistant to the latest dev version. + +### Set Home Assistant Version + +This allows you to specify a version of Home Assistant to install inside the devcontainer. + +### Home Assistant Config Check + +This runs a config check to make sure your config is valid. diff --git a/.devcontainer/configuration.yaml b/.devcontainer/configuration.yaml new file mode 100644 index 0000000..e23103f --- /dev/null +++ b/.devcontainer/configuration.yaml @@ -0,0 +1,12 @@ +default_config: +logger: + default: error + logs: + custom_components.yahoofinance: debug + + +sensor: + platform: yahoofinance + show_trending_icon: True + symbols: + - ISTNX \ No newline at end of file diff --git a/.devcontainer/custom_component_helper b/.devcontainer/custom_component_helper new file mode 100644 index 0000000..40165d9 --- /dev/null +++ b/.devcontainer/custom_component_helper @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +function StartHomeAssistant { + echo "Copy configuration.yaml" + cp -f .devcontainer/configuration.yaml /config || echo ".devcontainer/configuration.yaml are missing!" exit 1 + + echo "Copy the custom component" + rm -R /config/custom_components/ || echo "" + cp -r custom_components /config/custom_components/ || echo "Could not copy the custom_component" exit 1 + + echo "Start Home Assistant" + hass -c /config +} + +function UpdgradeHomeAssistantDev { + python -m pip install --upgrade git+git://github.com/home-assistant/home-assistant.git@dev +} + +function SetHomeAssistantVersion { + read -p 'Version: ' version + python -m pip install --upgrade homeassistant==$version +} + +function HomeAssistantConfigCheck { + hass -c /config --script check_config +} \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..012c39d --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,24 @@ +// See https://aka.ms/vscode-remote/devcontainer.json for format details. +{ + "context": "..", + "dockerFile": "Dockerfile", + "appPort": "8124:8123", + "runArgs": [ + "-e", + "GIT_EDTIOR='code --wait'" + ], + "extensions": [ + "ms-python.python", + "spmeesseman.vscode-taskexplorer" + ], + "settings": { + "python.pythonPath": "/usr/local/bin/python", + "python.linting.pylintEnabled": true, + "python.linting.enabled": true, + "python.formatting.provider": "black", + "editor.formatOnPaste": false, + "editor.formatOnSave": true, + "editor.formatOnType": true, + "files.trimTrailingWhitespace": true + } +} \ No newline at end of file diff --git a/.devcontainer/images/reopen.png b/.devcontainer/images/reopen.png new file mode 100644 index 0000000..cbcec3c Binary files /dev/null and b/.devcontainer/images/reopen.png differ diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index de288e1..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "python.formatting.provider": "black" -} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..22d4136 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,61 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Start Home Assistant on port 8124", + "type": "shell", + "command": "source .devcontainer/custom_component_helper && StartHomeAssistant", + "group": { + "kind": "test", + "isDefault": true + }, + "presentation": { + "reveal": "always", + "panel": "new" + }, + "problemMatcher": [] + }, + { + "label": "Upgrade Home Assistant to latest dev", + "type": "shell", + "command": "source .devcontainer/custom_component_helper && UpdgradeHomeAssistantDev", + "group": { + "kind": "test", + "isDefault": true + }, + "presentation": { + "reveal": "always", + "panel": "new" + }, + "problemMatcher": [] + }, + { + "label": "Set Home Assistant Version", + "type": "shell", + "command": "source .devcontainer/custom_component_helper && SetHomeAssistantVersion", + "group": { + "kind": "test", + "isDefault": true + }, + "presentation": { + "reveal": "always", + "panel": "new" + }, + "problemMatcher": [] + }, + { + "label": "Home Assistant Config Check", + "type": "shell", + "command": "source .devcontainer/custom_component_helper && HomeAssistantConfigCheck", + "group": { + "kind": "test", + "isDefault": true + }, + "presentation": { + "reveal": "always", + "panel": "new" + }, + "problemMatcher": [] + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index f7cee35..ba45b57 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,39 @@ -# Summary -A custom component to get stock updates from Yahoo finance. - -# Installation - -This can be installed by copying all the files from `custom_components/yahoofinance/` to `/custom_components/yahoofinance/`. - -Next you would define the symbols to be tracked in `configuration.yaml` - -Example: - -```yaml -sensor: - platform: yahoofinance - scan_interval: - hours: 4 - symbols: - - ISTNX - -``` - -The above configuration will generate an entity with the id `yahoofinance.istnx` and current value as the state along with these attributes: - -``` -attribution: Data provided by Yahoo Finance -currencySymbol: $ -symbol: ISTNX -fiftyDayAverage: ... -previousClose: ... -unit_of_measurement: USD -friendly_name: Ivy Science & Technology Fund C -icon: mdi:currency-usd -``` - -`scan_interval` is optional and the default value is 6 hours. - - +# Summary +A custom component to get stock updates from Yahoo finance. + +# Installation + +This can be installed by copying all the files from `custom_components/yahoofinance/` to `/custom_components/yahoofinance/`. + +Next you would define the symbols to be tracked in `configuration.yaml` + +Example: + +```yaml +sensor: + platform: yahoofinance + show_trending_icon: true + scan_interval: + hours: 4 + symbols: + - ISTNX + +``` + +The above configuration will generate an entity with the id `yahoofinance.istnx` and current value as the state along with these attributes: + +``` +attribution: Data provided by Yahoo Finance +currencySymbol: $ +symbol: ISTNX +fiftyDayAverage: ... +previousClose: ... +unit_of_measurement: USD +friendly_name: Ivy Science & Technology Fund C +icon: mdi:currency-usd +``` + +`scan_interval` is optional and the default value is 6 hours. Trending icon (up, down or neutral) can be used instead of currency based +icon by specifying `show_trending_icon`. + The component also exposes the service `yahoofinance.refresh_symbols` which will refresh all the data. \ No newline at end of file diff --git a/custom_components/yahoofinance/const.py b/custom_components/yahoofinance/const.py index d0efc67..a6081cc 100644 --- a/custom_components/yahoofinance/const.py +++ b/custom_components/yahoofinance/const.py @@ -1,37 +1,38 @@ -"""Constants for Yahoo Finance sensor.""" - -ATTR_CURRENCY_SYMBOL = "currencySymbol" -ATTR_FIFTY_DAY_AVERAGE = "fiftyDayAverage" -ATTR_FIFTY_DAY_SYMBOL = "symbol" -ATTR_PREVIOUS_CLOSE = "previousClose" -ATTRIBUTION = "Data provided by Yahoo Finance" -BASE = "https://query1.finance.yahoo.com/v7/finance/quote?symbols=" -CONF_SYMBOLS = "symbols" -DEFAULT_CURRENCY = "USD" -DEFAULT_CURRENCY_SYMBOL = "$" -DEFAULT_ICON = "mdi:currency-usd" -DOMAIN = "yahoofinance" -SERVICE_REFRESH = "refresh_symbols" - -CURRENCY_CODES = { - "bdt": "৳", - "brl": "R$", - "btc": "₿", - "cny": "¥", - "eth": "Ξ", - "eur": "€", - "gbp": "£", - "ils": "₪", - "inr": "₹", - "jpy": "¥", - "krw": "₩", - "kzt": "лв", - "ngn": "₦", - "php": "₱", - "rial": "﷼", - "rub": "₽", - "sign": "", - "try": "₺", - "twd": "$", - "usd": "$", -} +"""Constants for Yahoo Finance sensor.""" + +ATTR_CURRENCY_SYMBOL = "currencySymbol" +ATTR_FIFTY_DAY_AVERAGE = "fiftyDayAverage" +ATTR_FIFTY_DAY_SYMBOL = "symbol" +ATTR_PREVIOUS_CLOSE = "previousClose" +ATTRIBUTION = "Data provided by Yahoo Finance" +BASE = "https://query1.finance.yahoo.com/v7/finance/quote?symbols=" +CONF_SHOW_TRENDING_ICON = "show_trending_icon" +CONF_SYMBOLS = "symbols" +DEFAULT_CURRENCY = "USD" +DEFAULT_CURRENCY_SYMBOL = "$" +DEFAULT_ICON = "mdi:currency-usd" +DOMAIN = "yahoofinance" +SERVICE_REFRESH = "refresh_symbols" + +CURRENCY_CODES = { + "bdt": "৳", + "brl": "R$", + "btc": "₿", + "cny": "¥", + "eth": "Ξ", + "eur": "€", + "gbp": "£", + "ils": "₪", + "inr": "₹", + "jpy": "¥", + "krw": "₩", + "kzt": "лв", + "ngn": "₦", + "php": "₱", + "rial": "﷼", + "rub": "₽", + "sign": "", + "try": "₺", + "twd": "$", + "usd": "$", +} diff --git a/custom_components/yahoofinance/sensor.py b/custom_components/yahoofinance/sensor.py index fe710fb..339ad7b 100644 --- a/custom_components/yahoofinance/sensor.py +++ b/custom_components/yahoofinance/sensor.py @@ -10,13 +10,17 @@ import aiohttp import async_timeout -import homeassistant.helpers.config_validation as cv import voluptuous as vol + +import homeassistant.helpers.config_validation as cv from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import ATTR_ATTRIBUTION, CONF_SCAN_INTERVAL from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.entity import Entity, async_generate_entity_id -from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed +from homeassistant.helpers.update_coordinator import ( + DataUpdateCoordinator, + UpdateFailed, +) from .const import ( ATTR_CURRENCY_SYMBOL, @@ -25,6 +29,7 @@ ATTR_PREVIOUS_CLOSE, ATTRIBUTION, BASE, + CONF_SHOW_TRENDING_ICON, CONF_SYMBOLS, CURRENCY_CODES, DEFAULT_CURRENCY, @@ -38,12 +43,15 @@ ENTITY_ID_FORMAT = DOMAIN + ".{}" SCAN_INTERVAL = timedelta(hours=6) DEFAULT_TIMEOUT = 10 - +DEFAULT_CONF_SHOW_TRENDING_ICON = False PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( { vol.Required(CONF_SYMBOLS): vol.All(cv.ensure_list, [cv.string]), vol.Optional(CONF_SCAN_INTERVAL, default=SCAN_INTERVAL): cv.time_period, + vol.Optional( + CONF_SHOW_TRENDING_ICON, default=DEFAULT_CONF_SHOW_TRENDING_ICON + ): cv.boolean, } ) @@ -53,6 +61,10 @@ async def async_setup_platform( ): # pylint: disable=unused-argument """Set up the Yahoo Finance sensors.""" symbols = config.get(CONF_SYMBOLS, []) + show_trending_icon = config.get( + CONF_SHOW_TRENDING_ICON, DEFAULT_CONF_SHOW_TRENDING_ICON + ) + coordinator = YahooSymbolUpdateCoordinator( symbols, hass, config.get(CONF_SCAN_INTERVAL) ) @@ -60,7 +72,9 @@ async def async_setup_platform( sensors = [] for symbol in symbols: - sensors.append(YahooFinanceSensor(coordinator, symbol, hass)) + sensors.append( + YahooFinanceSensor(hass, coordinator, symbol, show_trending_icon) + ) # The True param fetches data first time before being written to HA async_add_entities(sensors, True) @@ -92,11 +106,12 @@ class YahooFinanceSensor(Entity): _state = None _symbol = None - def __init__(self, coordinator, symbol, hass) -> None: + def __init__(self, hass, coordinator, symbol, show_trending_icon) -> None: """Initialize the sensor.""" self._symbol = symbol self._coordinator = coordinator self.entity_id = async_generate_entity_id(ENTITY_ID_FORMAT, symbol, hass=hass) + self.show_trending_icon = show_trending_icon _LOGGER.debug("Created %s", self.entity_id) @property @@ -159,9 +174,19 @@ def fetch_data(self) -> None: self._currency = currency.upper() lower_currency = self._currency.lower() - self._icon = "mdi:currency-" + lower_currency - if lower_currency in CURRENCY_CODES: + + # Fall back to currency based icon if there is no _previous_close value + if self.show_trending_icon and not (self._previous_close is None): + if self._state > self._previous_close: + self._icon = "mdi:trending-up" + elif self._state < self._previous_close: + self._icon = "mdi:trending-down" + else: + self._icon = "mdi:trending-neutral" + else: self._icon = "mdi:currency-" + lower_currency + + if lower_currency in CURRENCY_CODES: self._currency_symbol = CURRENCY_CODES[lower_currency] @property