From 2346cddca29b9f2981e193d099021fa0ee7c96a1 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Thu, 14 Mar 2019 17:14:31 +0100 Subject: [PATCH] :sparkles: :tada: Initial library code --- .gitlab-ci.yml | 84 ++++ LICENSE.md | 2 +- README.md | 7 +- lib/addons.sh | 1005 ++++++++++++++++++++++++++++++++++++++++++ lib/api.sh | 103 +++++ lib/bashio | 26 ++ lib/bashio.sh | 80 ++++ lib/cache.sh | 108 +++++ lib/color.sh | 253 +++++++++++ lib/config.sh | 603 +++++++++++++++++++++++++ lib/const.sh | 83 ++++ lib/exit.sh | 89 ++++ lib/fs.sh | 80 ++++ lib/hardware.sh | 78 ++++ lib/hassos.sh | 172 ++++++++ lib/homeassistant.sh | 323 ++++++++++++++ lib/host.sh | 135 ++++++ lib/info.sh | 110 +++++ lib/jq.sh | 173 ++++++++ lib/log.sh | 128 ++++++ lib/pwned.sh | 140 ++++++ lib/repositories.sh | 106 +++++ lib/secrets.sh | 61 +++ lib/string.sh | 96 ++++ lib/supervisor.sh | 304 +++++++++++++ lib/var.sh | 156 +++++++ 26 files changed, 4499 insertions(+), 6 deletions(-) create mode 100644 .gitlab-ci.yml create mode 100644 lib/addons.sh create mode 100644 lib/api.sh create mode 100755 lib/bashio create mode 100644 lib/bashio.sh create mode 100644 lib/cache.sh create mode 100644 lib/color.sh create mode 100644 lib/config.sh create mode 100644 lib/const.sh create mode 100644 lib/exit.sh create mode 100644 lib/fs.sh create mode 100644 lib/hardware.sh create mode 100644 lib/hassos.sh create mode 100644 lib/homeassistant.sh create mode 100644 lib/host.sh create mode 100644 lib/info.sh create mode 100644 lib/jq.sh create mode 100644 lib/log.sh create mode 100644 lib/pwned.sh create mode 100644 lib/repositories.sh create mode 100644 lib/secrets.sh create mode 100644 lib/string.sh create mode 100644 lib/supervisor.sh create mode 100644 lib/var.sh diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..7855042 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,84 @@ +--- +image: docker:latest + +variables: + DOCKER_DRIVER: overlay2 + +stages: + - preflight + +# Generic DIND template +.dind: &dind + before_script: + - docker info + services: + - name: docker:dind + command: ["--experimental"] + +# Generic preflight template +.preflight: &preflight + stage: preflight + tags: + - preflight + +# Preflight jobs +shellcheck: + <<: *preflight + image: + name: koalaman/shellcheck-alpine:stable + entrypoint: [""] + before_script: + - shellcheck --version + - apk --no-cache add grep + - | + find . -type f -print0 | \ + xargs -0 sed -i 's:#!/usr/bin/with-contenv bash:#!/bin/bash:g' + script: + - | + for file in $(grep -IRl "#\!\(/usr/bin/env \|/bin/\)" --exclude-dir ".git" "${ADDON_TARGET}"); do + if ! shellcheck $file; then + export FAILED=1 + else + echo "$file OK" + fi + done + if [ "${FAILED}" = "1" ]; then + exit 1 + fi + +yamllint: + <<: *preflight + image: sdesbure/yamllint + before_script: + - yamllint --version + script: + - yamllint . + +jsonlint: + <<: *preflight + image: sahsu/docker-jsonlint + before_script: + - jsonlint --version || true + script: + - | + for file in $(find . -type f -name "*.json"); do + if ! jsonlint -q $file; then + export FAILED=1 + else + echo "$file OK" + fi + done + if [ "${FAILED}" = "1" ]; then + exit 1 + fi + +markdownlint: + <<: *preflight + image: + name: ruby:alpine + entrypoint: [""] + before_script: + - gem install mdl + - mdl --version + script: + - mdl --style all --warnings . diff --git a/LICENSE.md b/LICENSE.md index 3ea8973..05c00f7 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ # MIT License -Copyright (c) 2018 Franck Nijhof +Copyright (c) 2019 Franck Nijhof Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index e6087ac..2376f82 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,6 @@ ![Project Maintenance][maintenance-shield] [![GitHub Activity][commits-shield]][commits] -[![Bountysource][bountysource-shield]][bountysource] [![Discord][discord-shield]][discord] [![Buy me a coffee][buymeacoffee-shield]][buymeacoffee] @@ -98,7 +97,7 @@ check [the contributor's page][contributors]. MIT License -Copyright (c) 2018 Franck Nijhof +Copyright (c) 2019 Franck Nijhof Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -118,8 +117,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -[bountysource-shield]: https://img.shields.io/bountysource/team/hassio-addons/activity.svg -[bountysource]: https://www.bountysource.com/teams/hassio-addons/issues [buymeacoffee-shield]: https://www.buymeacoffee.com/assets/img/guidelines/download-assets-sm-2.svg [buymeacoffee]: https://www.buymeacoffee.com/frenck [commits-shield]: https://img.shields.io/github/commit-activity/y/hassio-addons/bashio.svg @@ -133,7 +130,7 @@ SOFTWARE. [issue]: https://github.com/hassio-addons/bashio/issues [keepchangelog]: http://keepachangelog.com/en/1.0.0/ [license-shield]: https://img.shields.io/github/license/hassio-addons/bashio.svg -[maintenance-shield]: https://img.shields.io/maintenance/yes/2018.svg +[maintenance-shield]: https://img.shields.io/maintenance/yes/2019.svg [patreon-shield]: https://www.frenck.nl/images/patreon.png [patreon]: https://www.patreon.com/frenck [project-stage-shield]: https://img.shields.io/badge/project%20stage-experimental-yellow.svg diff --git a/lib/addons.sh b/lib/addons.sh new file mode 100644 index 0000000..86339a9 --- /dev/null +++ b/lib/addons.sh @@ -0,0 +1,1005 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== + +# ------------------------------------------------------------------------------ +# Reloads the add-ons. +# ------------------------------------------------------------------------------ +function bashio::addons.reload() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio POST /addons/reload + bashio::cache.flush_all +} + +# ------------------------------------------------------------------------------ +# Start the specified add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.start() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio POST "/addons/${slug}/start" +} + +# ------------------------------------------------------------------------------ +# Restart the specified add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.restart() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio POST "/addons/${slug}/restart" +} + +# ------------------------------------------------------------------------------ +# Stop the specified add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.stop() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio POST "/addons/${slug}/stop" +} + +# ------------------------------------------------------------------------------ +# Install the specified add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.install() { + local slug=${1} + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio POST "/addons/${slug}/install" +} + +# ------------------------------------------------------------------------------ +# Rebuild the specified add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.rebuild() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio POST "/addons/${slug}/rebuild" +} + +# ------------------------------------------------------------------------------ +# Uninstall the specified add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.uninstall() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio POST "/addons/${slug}/uninstall" +} + +# ------------------------------------------------------------------------------ +# Update the specified add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.update() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio POST "/addons/${slug}/update" +} + +# ------------------------------------------------------------------------------ +# RAW Docker log of the specified add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.log() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio GET "/addons/${slug}/log" true +} + +# ------------------------------------------------------------------------------ +# Returns the changelog of the add-on. +# +# Arguments: +# $1 Add-on slug (optional) +# ------------------------------------------------------------------------------ +function bashio::addon.changelog() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio GET "/addons/${slug}/changelog" true +} + +# ------------------------------------------------------------------------------ +# Returns a JSON object with generic version information about addons. +# +# Arguments: +# $1 Add-on slug (optional) +# $1 Cache key to store results in (optional) +# $2 jq Filter to apply on the result (optional) +# ------------------------------------------------------------------------------ +function bashio::addons() { + local slug=${1:-false} + local cache_key=${2:-'addons.list'} + local filter=${3:-'.addons[].slug'} + local info + local response + + bashio::log.trace "${FUNCNAME[0]}" "$@" + + if bashio::cache.exists "${cache_key}"; then + bashio::cache.get "${cache_key}" + return "${__BASHIO_EXIT_OK}" + fi + + if bashio::var.false "${slug}"; then + if bashio::cache.exists "addons.list"; then + info=$(bashio::cache.get 'addons.list') + else + info=$(bashio::api.hassio GET "/addons" false) + bashio::cache.set "addons.list" "${info}" + fi + else + if bashio::cache.exists "addons.${slug}.info"; then + info=$(bashio::cache.get "addons.${slug}.info") + else + info=$(bashio::api.hassio GET "/addons/${slug}/info" false) + bashio::cache.set "addons.${slug}.info" "${info}" + fi + fi + + response="${info}" + if bashio::var.has_value "${filter}"; then + response=$(bashio::jq "${info}" "${filter}") + fi + + bashio::cache.set "${cache_key}" "${response}" + printf "%s" "${response}" + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Returns a list of installed add-ons or for a specific add-ons. +# ------------------------------------------------------------------------------ +function bashio::addons.installed() { + local slug=${1:-false} + + bashio::log.trace "${FUNCNAME[0]}" "$@" + + if bashio::var.false "${slug}"; then + bashio::addons \ + false \ + 'addons.info.installed' \ + '.addons[] | select(.installed != null) | .slug' + else + bashio::addons \ + "${slug}" \ + "addons.${slug}.installed" \ + 'if (.version != null) then true else false end' + fi +} + +# ------------------------------------------------------------------------------ +# Returns the name of an add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.name() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.name" '.name' +} + +# ------------------------------------------------------------------------------ +# Returns the description of an add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.description() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.description" '.description' +} + +# ------------------------------------------------------------------------------ +# Returns the long description of an add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.long_description() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons \ + "${slug}" \ + "addons.${slug}.long_description" \ + '.long_description' +} + +# ------------------------------------------------------------------------------ +# Returns or sets whether or not auto update is enabled for this add-on. +# +# Arguments: +# $1 Add-on slug +# $2 Set current auto update state (Optional) +# ------------------------------------------------------------------------------ +function bashio::addon.auto_update() { + local slug=${1:-'self'} + local auto_update=${2:-} + + bashio::log.trace "${FUNCNAME[0]}" "$@" + + if bashio::var.has_value "${auto_update}"; then + auto_update=$(bashio::var.json auto_update "^${auto_update}") + bashio::api.hassio POST "/addons/${slug}/options" "${auto_update}" + bashio::cache.flush_all + else + bashio::addons \ + "${slug}" \ + "addons.${slug}.auto_update" \ + '.auto_update // false' + fi +} + +# ------------------------------------------------------------------------------ +# Returns the URL of an add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.url() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.url" '.url' +} + +# ------------------------------------------------------------------------------ +# Returns the deatched state of an add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.detached() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.detached" '.detached // false' +} + +# ------------------------------------------------------------------------------ +# Returns the availability state of an add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.available() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.available" '.available // false' +} + +# ------------------------------------------------------------------------------ +# Returns list of supported architectures by the add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.arch() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.arch" '.arch[]' +} + +# ------------------------------------------------------------------------------ +# Returns list of supported machine types by the add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.machine() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.machine" '.machine[]' +} + +# ------------------------------------------------------------------------------ +# Returns the slug of the repository this add-on is in. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.repository() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.repository" '.repository' +} + + +# ------------------------------------------------------------------------------ +# Returns the version of an add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.version() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.version" '.version' +} + +# ------------------------------------------------------------------------------ +# Returns the latest version of an add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.last_version() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.last_version" '.last_version' +} + +# ------------------------------------------------------------------------------ +# Checks if there is an update available for an add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.update_available() { + local addon=${1:-'self'} + local version + local last_version + + bashio::log.trace "${FUNCNAME[0]}" "$@" + + version=$(bashio::addons.version "${addon}") + last_version=$(bashio::addons.last_version "${addon}") + + if [[ "${version}" = "${last_version}" ]]; then + return "${__BASHIO_EXIT_NOK}" + fi + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Returns the current state of an add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.state() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.state" '.state' +} + +# ------------------------------------------------------------------------------ +# Returns the current boot setting of this add-on. +# +# Arguments: +# $1 Add-on slug +# $2 Sets boot setting (optional). +# ------------------------------------------------------------------------------ +function bashio::addon.boot() { + local slug=${1:-'self'} + local boot=${2:-} + + bashio::log.trace "${FUNCNAME[0]}" "$@" + + if bashio::var.has_value "${boot}"; then + boot=$(bashio::var.json boot "${boot}") + bashio::api.hassio POST "/addons/${slug}/options" "${boot}" + bashio::cache.flush_all + else + bashio::addons "${slug}" "addons.${slug}.boot" '.boot' + fi +} + +# ------------------------------------------------------------------------------ +# Returns whether or not this add-on is being build locally. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.build() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.build" '.build // false' +} + +# ------------------------------------------------------------------------------ +# Returns options for this add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.options() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.options" '.options' +} + +# ------------------------------------------------------------------------------ +# Returns a list of ports which are exposed on the host network for this add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.network() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.network" '.network' +} + +# ------------------------------------------------------------------------------ +# Returns whether or not this add-on runs on the host network. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.host_network() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons \ + "${slug}" \ + "addons.${slug}.host_network" \ + '.host_network // false' +} + +# ------------------------------------------------------------------------------ +# Returns whether or not this add-on runs on the host pid namespace. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.host_pid() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons \ + "${slug}" \ + "addons.${slug}.host_pid" \ + '.host_pid // false' +} + +# ------------------------------------------------------------------------------ +# Returns whether or not this add-on has IPC access. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.host_ipc() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons \ + "${slug}" \ + "addons.${slug}.host_ipc" \ + '.host_ipc // false' +} + +# ------------------------------------------------------------------------------ +# Returns whether or not this add-on has DBus access to the host. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.host_dbus() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons \ + "${slug}" \ + "addons.${slug}.host_dbus" \ + '.host_dbus // false' +} + +# ------------------------------------------------------------------------------ +# Returns the privileges the add-on has on to the hardware / system. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.privileged() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.privileged" '.privileged[]' +} + +# ------------------------------------------------------------------------------ +# Returns the current apparmor state of this add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.apparmor() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.apparmor" '.apparmor' +} + +# ------------------------------------------------------------------------------ +# Returns a list devices made available to the add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.devices() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.devices" '.devices // empty | .[]' +} + +# ------------------------------------------------------------------------------ +# Returns if UART was made available to the add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.auto_uart() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.auto_uart" '.auto_uart // false' +} + +# ------------------------------------------------------------------------------ +# Returns whether or not this add-on has a icon available. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.icon() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.icon" '.icon // false' +} + +# ------------------------------------------------------------------------------ +# Returns whether or not this add-on has a logo available. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.logo() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.logo" '.logo // false' +} + +# ------------------------------------------------------------------------------ +# Returns whether or not this add-on has a changelog available. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.changelog() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.changelog" '.changelog // false' +} + +# ------------------------------------------------------------------------------ +# Returns whether or not this add-on can access the Hass.io API. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.hassio_api() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.hassio_api" '.hassio_api // false' +} + +# ------------------------------------------------------------------------------ +# Returns the Hass.io API role of this add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.hassio_role() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.hassio_role" '.hassio_role' +} + +# ------------------------------------------------------------------------------ +# Returns whether or not this add-on can access the Home Assistant API. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.homeassistant_api() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons \ + "${slug}" \ + "addons.${slug}.homeassistant_api" \ + '.homeassistant_api // false' +} + +# ------------------------------------------------------------------------------ +# Returns whether or not this add-on can access the Hass.io Authentication API. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.auth_api() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.auth_api" '.auth_api // false' +} + +# ------------------------------------------------------------------------------ +# Returns whether or not this add-on run in protected mode. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.protected() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.protected" '.protected // false' +} + +# ------------------------------------------------------------------------------ +# Returns the add-on its rating +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.rating() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.rating" '.rating' +} + +# ------------------------------------------------------------------------------ +# Returns whether or not this add-on can use the STDIN on the Hass.io API. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.stdin() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.stdin" '.stdin // false' +} + +# ------------------------------------------------------------------------------ +# A URL for web interface of this add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.webui() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.webui" '.webui // empty' +} + +# ------------------------------------------------------------------------------ +# Returns whether or not this add-on can access GPIO. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.gpio() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.gpio" '.gpio // false' +} + +# ------------------------------------------------------------------------------ +# Returns whether or not this add-on can access kernel modules. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.kernel_modules() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons \ + "${slug}" \ + "addons.${slug}.kernel_modules" \ + '.kernel_modules // false' +} + +# ------------------------------------------------------------------------------ +# Returns whether or not this add-on can access the devicetree. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.devicetree() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.devicetree" '.devicetree // false' +} + +# ------------------------------------------------------------------------------ +# Returns whether or not this add-on can access the Docker socket. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.docker_api() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.docker_api" '.docker_api // false' +} + +# ------------------------------------------------------------------------------ +# Returns whether or not this add-on can access an audio device. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.audio() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons "${slug}" "addons.${slug}.audio" '.audio // false' +} + +# ------------------------------------------------------------------------------ +# Returns the available audio input device for an add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.audio_input() { + local slug=${1:-'self'} + local audio_input=${2:-} + + bashio::log.trace "${FUNCNAME[0]}" "$@" + + if bashio::var.has_value "${audio_input}"; then + audio_input=$(bashio::var.json audio_input "${audio_input}") + bashio::api.hassio POST "/addons/${slug}/options" "${audio_input}" + bashio::cache.flush_all + else + bashio::addons \ + "${slug}" \ + "addons.${slug}.audio_input" \ + '.audio_input // empty' + fi +} + +# ------------------------------------------------------------------------------ +# Returns the available audio output device for an add-on. +# +# Arguments: +# $1 Add-on slug +# $2 Audio output device to set (Optional) +# ------------------------------------------------------------------------------ +function bashio::addon.audio_output() { + local slug=${1:-'self'} + local audio_output=${2:-} + + bashio::log.trace "${FUNCNAME[0]}" "$@" + + if bashio::var.has_value "${audio_output}"; then + audio_output=$(bashio::var.json audio_output "${audio_output}") + bashio::api.hassio POST "/addons/${slug}/options" "${audio_output}" + bashio::cache.flush_all + else + bashio::addons \ + "${slug}" \ + "addons.${slug}.audio_output" \ + '.audio_output // empty' + fi +} + +# ------------------------------------------------------------------------------ +# List all available stats about an add-on. +# +# Arguments: +# $1 Add-on slug +# $1 Cache key to store results in (optional) +# $2 jq Filter to apply on the result (optional) +# ------------------------------------------------------------------------------ +function bashio::addon.stats() { + local slug=${1:-'self'} + local cache_key=${2:-"addons.${slug}.stats"} + local filter=${3:-} + local info + local response + + bashio::log.trace "${FUNCNAME[0]}" "$@" + + if bashio::cache.exists "${cache_key}"; then + bashio::cache.get "${cache_key}" + return "${__BASHIO_EXIT_OK}" + fi + + if bashio::cache.exists "addons.${slug}.stats"; then + info=$(bashio::cache.get "addons.${slug}.stats") + else + info=$(bashio::api.hassio GET "/addons/${slug}/stats" false) + bashio::cache.set "addons.${slug}.stats" "${info}" + fi + + response="${info}" + if bashio::var.has_value "${filter}"; then + response=$(bashio::jq "${info}" "${filter}") + fi + + bashio::cache.set "${cache_key}" "${response}" + printf "%s" "${response}" + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Returns CPU usage from the specified add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.cpu_percent() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons.stats \ + "${slug}" \ + "addons.${slug}.stats.cpu_percent" \ + '.cpu_percent' +} + +# ------------------------------------------------------------------------------ +# Returns memory usage from the specified add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.memory_usage() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons.stats \ + "${slug}" \ + "addons.${slug}.stats.memory_usage" \ + '.memory_usage' +} + +# ------------------------------------------------------------------------------ +# Returns memory limit from the specified add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.memory_limit() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons.stats \ + "${slug}" \ + "addons.${slug}.stats.memory_limit" \ + '.memory_limit' +} + +# ------------------------------------------------------------------------------ +# Returns outgoing network usage from the specified add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.network_tx() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons.stats \ + "${slug}" \ + "addons.${slug}.stats.network_tx" \ + '.network_tx' +} + +# ------------------------------------------------------------------------------ +# Returns incoming network usage from the specified add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.network_rx() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons.stats \ + "${slug}" \ + "addons.${slug}.stats.network_rx" \ + '.network_rx' +} + +# ------------------------------------------------------------------------------ +# Returns disk read usage from the specified add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.blk_read() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons.stats \ + "${slug}" \ + "addons.${slug}.stats.blk_read" \ + '.blk_read' +} + +# ------------------------------------------------------------------------------ +# Returns disk write usage from the specified add-on. +# +# Arguments: +# $1 Add-on slug +# ------------------------------------------------------------------------------ +function bashio::addon.blk_write() { + local slug=${1:-'self'} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::addons.stats \ + "${slug}" \ + "addons.${slug}.stats.blk_write" \ + '.blk_write' +} + +function bashio::require.protected() { + local protected + + protected=$(bashio::addon.protected) + if bashio::var.true "${protected}"; then + return "${__BASHIO_EXIT_OK}" + fi + + bashio::log.fatal "PROTECTION MODE IS DISABLED!" + bashio::log.fatal + bashio::log.fatal "We are trying to help you to protect your system the" + bashio::log.fatal "best we can. Therefore, this add-on checks if" + bashio::log.fatal "protection mode is enabled on this add-on." + bashio::log.fatal + bashio::log.fatal "Unfortunately, it has been disabled." + bashio::log.fatal "Pleas enable it again!" + bashio::log.fatal "" + bashio::log.fatal "Steps:" + bashio::log.fatal " - Go to the Hass.io Panel." + bashio::log.fatal " - Click on this add-on." + bashio::log.fatal " - Set the 'Protection mode' switch to on." + bashio::log.fatal " - Restart the add-on." + bashio::log.fatal + + bashio::exit.nok +} + +function bashio::require.unprotected() { + local protected + + protected=$(bashio::addon.protected) + if bashio::var.false "${protected}"; then + return "${__BASHIO_EXIT_OK}" + fi + + bashio::log.fatal "PROTECTION MODE IS ENABLED!" + bashio::log.fatal + bashio::log.fatal "To be able to use this add-on, you'll need to disable" + bashio::log.fatal "protection mode on this add-on. Without it, the add-on" + bashio::log.fatal "is unable to access Docker." + bashio::log.fatal + bashio::log.fatal "Steps:" + bashio::log.fatal " - Go to the Hass.io Panel." + bashio::log.fatal " - Click on this add-on." + bashio::log.fatal " - Set the 'Protection mode' switch to off." + bashio::log.fatal " - Restart the add-on." + bashio::log.fatal + bashio::log.fatal "Access to Docker allows you to do really powerful things" + bashio::log.fatal "including complete destruction of your system." + bashio::log.fatal "Please, be sure you know what you are doing before" + bashio::log.fatal "enabling this feature (and this add-on)!" + bashio::log.fatal + + bashio::exit.nok +} diff --git a/lib/api.sh b/lib/api.sh new file mode 100644 index 0000000..fb73498 --- /dev/null +++ b/lib/api.sh @@ -0,0 +1,103 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== + +# ------------------------------------------------------------------------------ +# Makes a call to the Hass.io API. +# +# Arguments: +# $1 HTTP Method (GET/POST) +# $2 API Resource requested +# $3 Whether or not this resource returns raw data instead of json (optional) +# $3 In case of a POST method, this parameter is the JSON to POST (optional) +# $4 jq filter command (optional) +# ------------------------------------------------------------------------------ +function bashio::api.hassio() { + local method=${1} + local resource=${2} + local raw=${3:-} + local filter=${4:-} + local auth_header='X-HASSIO-KEY;' + local response + local status + local data='{}' + local result + + bashio::log.trace "${FUNCNAME[0]}" "$@" + + if [[ -n "${HASSIO_TOKEN:-}" ]]; then + auth_header="X-HASSIO-KEY: ${__BASHIO_HASSIO_TOKEN}" + fi + + if [[ "${method}" = "POST" ]] && bashio::var.has_value "${raw}"; then + data="${raw}" + fi + + if ! response=$(curl --silent --show-error \ + --write-out '\n%{http_code}' --request "${method}" \ + -H "${auth_header}" \ + -H "Content-Type: application/json" \ + -d "${data}" \ + "${__BASHIO_HASSIO_API}${resource}" + ); then + bashio::log.debug "${response}" + bashio::log.error "Something went wrong contacting the API" + return "${__BASHIO_EXIT_NOK}" + fi + + status=${response##*$'\n'} + response=${response%$status} + + bashio::log.debug "Requested API resource: ${__BASHIO_HASSIO_API}${resource}" + bashio::log.debug "Request method: ${method}" + bashio::log.debug "Request data: ${data}" + bashio::log.debug "API HTTP Response code: ${status}" + bashio::log.debug "API Response: ${response}" + + if [[ "${status}" -eq 401 ]]; then + bashio::log.error "Unable to authenticate with the API, permission denied" + return "${__BASHIO_EXIT_NOK}" + fi + + if [[ "${status}" -eq 404 ]]; then + bashio::log.error "Requested resource ${resource} was not found" + return "${__BASHIO_EXIT_NOK}" + fi + + if [[ "${status}" -eq 405 ]]; then + bashio::log.error "Requested resource ${resource} was called using an" \ + "unallowed method." + return "${__BASHIO_EXIT_NOK}" + fi + + if [[ $(bashio::jq "${response}" ".result") = "error" ]]; then + bashio::log.error "Got unexpected response from the API:" \ + "$(bashio::jq "${response}" '.message // empty')" + return "${__BASHIO_EXIT_NOK}" + fi + + if [[ "${status}" -ne 200 ]]; then + bashio::log.error "Unknown HTTP error occured" + return "${__BASHIO_EXIT_NOK}" + fi + + if bashio::var.true "${raw}"; then + echo "${response}" + return "${__BASHIO_EXIT_NOK}" + fi + + result=$(bashio::jq "${response}" 'if .data == {} then empty else .data end') + + if bashio::var.has_value "${filter}"; then + bashio::log.debug "Filtering response using: ${filter}" + result=$(bashio::jq "${result}" "${filter}") + fi + + echo "${result}" + return "${__BASHIO_EXIT_OK}" +} diff --git a/lib/bashio b/lib/bashio new file mode 100755 index 0000000..39d73ce --- /dev/null +++ b/lib/bashio @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== +set -o errexit # Exit script when a command exits with non-zero status +set -o errtrace # Exit on error inside any functions or sub-shells +set -o nounset # Exit script on use of an undefined variable +set -o pipefail # Return exit status of the last command in the pipe that failed + +export __BASHIO_BIN +export __BASHIO_LIB_DIR + +__BASHIO_BIN=$(readlink -f "${BASH_SOURCE[0]}") +__BASHIO_LIB_DIR=$(dirname "${__BASHIO_BIN}") + +# Include Bashio library +# shellcheck source=bashio.sh +source "${__BASHIO_LIB_DIR}/bashio.sh" + +# Execute source +# shellcheck source=/dev/null +source "$@" diff --git a/lib/bashio.sh b/lib/bashio.sh new file mode 100644 index 0000000..bc18fcc --- /dev/null +++ b/lib/bashio.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== +set -o errexit # Exit script when a command exits with non-zero status +set -o errtrace # Exit on error inside any functions or sub-shells +set -o nounset # Exit script on use of an undefined variable +set -o pipefail # Return exit status of the last command in the pipe that failed + +# ============================================================================== +# GLOBALS +# ============================================================================== + +# Bashio version number +readonly BASHIO_VERSION="0.1.0" + +# Stores the location of this library +readonly __BASHIO_LIB_DIR=$(dirname "${BASH_SOURCE[0]}") + +# shellcheck source=const.sh +source "${__BASHIO_LIB_DIR}/const.sh" + +# Defaults +declare __BASHIO_HASSIO_API=${HASSIO_API:-${__BASHIO_DEFAULT_HASSIO_API}} +declare __BASHIO_HASSIO_TOKEN=${HASSIO_TOKEN:-${__BASHIO_DEFAULT_HASSIO_TOKEN}} +declare __BASHIO_ADDON_CONFIG=${HASSIO_ADDON_CONFIG:-${__BASHIO_DEFAULT_ADDON_CONFIG}} +declare __BASHIO_LOG_LEVEL=${LOG_LEVEL:-${__BASHIO_DEFAULT_LOG_LEVEL}} +declare __BASHIO_LOG_FORMAT=${LOG_FORMAT:-${__BASHIO_DEFAULT_LOG_FORMAT}} +declare __BASHIO_LOG_TIMESTAMP=${LOG_TIMESTAMP:-${__BASHIO_DEFAULT_LOG_TIMESTAMP}} +declare __BASHIO_HIBP_ENDPOINT=${HIBP_ENDPOINT:-${__BASHIO_DEFAULT_HIBP_ENDPOINT}} +declare __BASHIO_CACHE_DIR=${CACHE_DIR:-${__BASHIO_DEFAULT_CACHE_DIR}} +declare __BASHIO_HA_SECRETS=${HA_SECRETS:-${__BASHIO_DEFAULT_SECRETS}} + +# ============================================================================== +# MODULES +# ============================================================================== +# shellcheck source=color.sh +source "${__BASHIO_LIB_DIR}/color.sh" +# shellcheck source=log.sh +source "${__BASHIO_LIB_DIR}/log.sh" + +# shellcheck source=fs.sh +source "${__BASHIO_LIB_DIR}/fs.sh" +# shellcheck source=cache.sh +source "${__BASHIO_LIB_DIR}/cache.sh" + +# shellcheck source=addons.sh +source "${__BASHIO_LIB_DIR}/addons.sh" +# shellcheck source=api.sh +source "${__BASHIO_LIB_DIR}/api.sh" +# shellcheck source=config.sh +source "${__BASHIO_LIB_DIR}/config.sh" +# shellcheck source=exit.sh +source "${__BASHIO_LIB_DIR}/exit.sh" +# shellcheck source=hardware.sh +source "${__BASHIO_LIB_DIR}/hardware.sh" +# shellcheck source=hassos.sh +source "${__BASHIO_LIB_DIR}/hassos.sh" +# shellcheck source=homeassistant.sh +source "${__BASHIO_LIB_DIR}/homeassistant.sh" +# shellcheck source=host.sh +source "${__BASHIO_LIB_DIR}/host.sh" +# shellcheck source=info.sh +source "${__BASHIO_LIB_DIR}/info.sh" +# shellcheck source=jq.sh +source "${__BASHIO_LIB_DIR}/jq.sh" +# shellcheck source=pwned.sh +source "${__BASHIO_LIB_DIR}/pwned.sh" +# shellcheck source=repositories.sh +source "${__BASHIO_LIB_DIR}/repositories.sh" +# shellcheck source=secrets.sh +source "${__BASHIO_LIB_DIR}/secrets.sh" +# shellcheck source=supervisor.sh +source "${__BASHIO_LIB_DIR}/supervisor.sh" +# shellcheck source=var.sh +source "${__BASHIO_LIB_DIR}/var.sh" diff --git a/lib/cache.sh b/lib/cache.sh new file mode 100644 index 0000000..e51a2df --- /dev/null +++ b/lib/cache.sh @@ -0,0 +1,108 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== + +# ------------------------------------------------------------------------------ +# Check if a cache key exists in the cache +# +# Arguments: +# $1 Cache key +# ------------------------------------------------------------------------------ +function bashio::cache.exists() { + local key=${1} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if bashio::fs.file_exists "${__BASHIO_CACHE_DIR}/${key}.cache"; then + return "${__BASHIO_EXIT_OK}" + fi + + return "${__BASHIO_EXIT_NOK}" +} + +# ------------------------------------------------------------------------------ +# Returns the cached value based on a key +# +# Arguments: +# $1 Cache key +# ------------------------------------------------------------------------------ +function bashio::cache.get() { + local key=${1} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if ! bashio::cache.exists "${key}"; then + return "${__BASHIO_EXIT_NOK}" + fi + + printf "%s" "$(<${__BASHIO_CACHE_DIR}/"${key}".cache)" + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Cache a value identified by a given key +# +# Arguments: +# $1 Cache key +# $2 Cache value +# ------------------------------------------------------------------------------ +function bashio::cache.set() { + local key=${1} + local value=${2} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if ! bashio::fs.directory_exists "${__BASHIO_CACHE_DIR}"; then + mkdir -p "${__BASHIO_CACHE_DIR}" || + basshio::exit.nok "Could not create cache folder" + fi + + if ! printf "%s" "$value" > "${__BASHIO_CACHE_DIR}/${key}.cache"; then + bashio::log.warning "An error occured while storing ${key} to cache" + return "${__BASHIO_EXIT_NOK}" + fi + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Remove a specific item from the cache based on the caching key +# +# Arguments: +# $1 Cache key +# ------------------------------------------------------------------------------ +function bashio::cache.flush() { + local key=${1} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if ! rm -f "${__BASHIO_CACHE_DIR}/${key}.cache"; then + bashio::exit.nok "An error while flushing ${key} from cache" + return "${__BASHIO_EXIT_NOK}" + fi + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Flush all cached data +# ------------------------------------------------------------------------------ +bashio::cache.flush_all() { + bashio::log.trace "${FUNCNAME[0]}" + + if ! bashio::fs.directory_exists "${__BASHIO_CACHE_DIR}"; then + return "${__BASHIO_EXIT_OK}" + fi + + if ! rm -f -r "${__BASHIO_CACHE_DIR}"; then + basshio::exit.nok "Could not flush cache" + return "${__BASHIO_EXIT_NOK}" + fi + + return "${__BASHIO_EXIT_OK}" +} diff --git a/lib/color.sh b/lib/color.sh new file mode 100644 index 0000000..2e869ae --- /dev/null +++ b/lib/color.sh @@ -0,0 +1,253 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== + +# ------------------------------------------------------------------------------ +# Reset color output (background and foreground colors). +# ------------------------------------------------------------------------------ +function bashio::color.reset() { + echo -n -e "${__BASHIO_COLORS_RESET}" +} + +# ------------------------------------------------------------------------------ +# Set default output color. +# ------------------------------------------------------------------------------ +function bashio::color.default() { + echo -n -e "${__BASHIO_COLORS_DEFAULT}" +} + +# ------------------------------------------------------------------------------ +# Set font output color to black. +# ------------------------------------------------------------------------------ +function bashio::color.black() { + echo -n -e "${__BASHIO_COLORS_BLACK}" +} + +# ------------------------------------------------------------------------------ +# Set font output color to red. +# ------------------------------------------------------------------------------ +function bashio::color.red() { + echo -n -e "${__BASHIO_COLORS_RED}" +} + +# ------------------------------------------------------------------------------ +# Set font output color to green. +# ------------------------------------------------------------------------------ +function bashio::color.green() { + echo -n -e "${__BASHIO_COLORS_GREEN}" +} + +# ------------------------------------------------------------------------------ +# Set font output color to yellow. +# ------------------------------------------------------------------------------ +function bashio::color.yellow() { + echo -n -e "${__BASHIO_COLORS_YELLOW}" +} + +# ------------------------------------------------------------------------------ +# Set font output color to blue. +# ------------------------------------------------------------------------------ +function bashio::color.blue() { + echo -n -e "${__BASHIO_COLORS_BLUE}" +} + +# ------------------------------------------------------------------------------ +# Set font output color to magenta. +# ------------------------------------------------------------------------------ +function bashio::color.magenta() { + echo -n -e "${__BASHIO_COLORS_MAGENTA}" +} + +# ------------------------------------------------------------------------------ +# Set font output color to cyan. +# ------------------------------------------------------------------------------ +function bashio::color.cyan() { + echo -n -e "${__BASHIO_COLORS_CYAN}" +} + +# ------------------------------------------------------------------------------ +# Set font output color to light grey. +# ------------------------------------------------------------------------------ +function bashio::color.light_grey() { + echo -n -e "${__BASHIO_COLORS_LIGHT_GRAY}" +} + +# ------------------------------------------------------------------------------ +# Set font output color to dark grey. +# ------------------------------------------------------------------------------ +function bashio::color.dark_grey() { + echo -n -e "${__BASHIO_COLORS_DARK_GRAY}" +} + +# ------------------------------------------------------------------------------ +# Set font output color to light red. +# ------------------------------------------------------------------------------ +function bashio::color.light_red() { + echo -n -e "${__BASHIO_COLORS_LIGHT_RED}" +} + +# ------------------------------------------------------------------------------ +# Set font output color to light green. +# ------------------------------------------------------------------------------ +function bashio::color.light_green() { + echo -n -e "${__BASHIO_COLORS_LIGHT_GREEN}" +} + +# ------------------------------------------------------------------------------ +# Set font output color to light yellow. +# ------------------------------------------------------------------------------ +function bashio::color.light_yellow() { + echo -n -e "${__BASHIO_COLORS_LIGHT_YELLOW}" +} + +# ------------------------------------------------------------------------------ +# Set font output color to light blue. +# ------------------------------------------------------------------------------ +function bashio::color.light_blue() { + echo -n -e "${__BASHIO_COLORS_LIGHT_BLUE}" +} + +# ------------------------------------------------------------------------------ +# Set font output color to light magenta. +# ------------------------------------------------------------------------------ +function bashio::color.light_magenta() { + echo -n -e "${__BASHIO_COLORS_LIGHT_MAGENTA}" +} + +# ------------------------------------------------------------------------------ +# Set font output color to light cyan. +# ------------------------------------------------------------------------------ +function bashio::color.light_cyan() { + echo -n -e "${__BASHIO_COLORS_LIGHT_CYAN}" +} + +# ------------------------------------------------------------------------------ +# Set font output color to white. +# ------------------------------------------------------------------------------ +function bashio::color.white() { + echo -n -e "${__BASHIO_COLORS_WHITE}" +} + +# ------------------------------------------------------------------------------ +# Set font output color background to default. +# ------------------------------------------------------------------------------ +function bashio::color.bg.default() { + echo -n -e "${__BASHIO_COLORS_BG_DEFAULT}" +} + +# ------------------------------------------------------------------------------ +# Set font output color background to black. +# ------------------------------------------------------------------------------ +function bashio::color.bg.black() { + echo -n -e "${__BASHIO_COLORS_BG_BLACK}" +} + +# ------------------------------------------------------------------------------ +# Set font output color background to red. +# ------------------------------------------------------------------------------ +function bashio::color.bg.red() { + echo -n -e "${__BASHIO_COLORS_BG_RED}" +} + +# ------------------------------------------------------------------------------ +# Set font output color background to green. +# ------------------------------------------------------------------------------ +function bashio::color.bg.green() { + echo -n -e "${__BASHIO_COLORS_BG_GREEN}" +} + +# ------------------------------------------------------------------------------ +# Set font output color background to yellow. +# ------------------------------------------------------------------------------ +function bashio::color.bg.yellow() { + echo -n -e "${__BASHIO_COLORS_BG_YELLOW}" +} + +# ------------------------------------------------------------------------------ +# Set font output color background to blue. +# ------------------------------------------------------------------------------ +function bashio::color.bg.blue() { + echo -n -e "${__BASHIO_COLORS_BG_BLUE}" +} + +# ------------------------------------------------------------------------------ +# Set font output color background to magenta. +# ------------------------------------------------------------------------------ +function bashio::color.bg.magenta() { + echo -n -e "${__BASHIO_COLORS_BG_MAGENTA}" +} + +# ------------------------------------------------------------------------------ +# Set font output color background to cyan. +# ------------------------------------------------------------------------------ +function bashio::color.bg.cyan() { + echo -n -e "${__BASHIO_COLORS_BG_CYAN}" +} + +# ------------------------------------------------------------------------------ +# Set font output color background to light gray. +# ------------------------------------------------------------------------------ +function bashio::color.bg.light_gray() { + echo -n -e "${__BASHIO_COLORS_BG_LIGHT_GRAY}" +} + +# ------------------------------------------------------------------------------ +# Set font output color background to dark gray. +# ------------------------------------------------------------------------------ +function bashio::color.bg.dark_gray() { + echo -n -e "${__BASHIO_COLORS_BG_DARK_GRAY}" +} + +# ------------------------------------------------------------------------------ +# Set font output color background to light red. +# ------------------------------------------------------------------------------ +function bashio::color.bg.light_red() { + echo -n -e "${__BASHIO_COLORS_BG_LIGHT_RED}" +} + +# ------------------------------------------------------------------------------ +# Set font output color background to light green. +# ------------------------------------------------------------------------------ +function bashio::color.bg.light_green() { + echo -n -e "${__BASHIO_COLORS_BG_LIGHT_GREEN}" +} + +# ------------------------------------------------------------------------------ +# Set font output color background to light yellow. +# ------------------------------------------------------------------------------ +function bashio::color.bg.light_yellow() { + echo -n -e "${__BASHIO_COLORS_BG_LIGHT_YELLOW}" +} + +# ------------------------------------------------------------------------------ +# Set font output color background to light blue. +# ------------------------------------------------------------------------------ +function bashio::color.bg.light_blue() { + echo -n -e "${__BASHIO_COLORS_BG_LIGHT_BLUE}" +} + +# ------------------------------------------------------------------------------ +# Set font output color background to light magenta. +# ------------------------------------------------------------------------------ +function bashio::color.bg.light_magenta() { + echo -n -e "${__BASHIO_COLORS_BG_LIGHT_MAGENTA}" +} + +# ------------------------------------------------------------------------------ +# Set font output color background to light cyan. +# ------------------------------------------------------------------------------ +function bashio::color.bg.light_cyan() { + echo -n -e "${__BASHIO_COLORS_BG_LIGHT_CYAN}" +} + +# ------------------------------------------------------------------------------ +# Set font output color background to light white. +# ------------------------------------------------------------------------------ +function bashio::color.bg.light_white() { + echo -n -e "${__BASHIO_COLORS_BG_LIGHT_WHITE}" +} diff --git a/lib/config.sh b/lib/config.sh new file mode 100644 index 0000000..e01e6ee --- /dev/null +++ b/lib/config.sh @@ -0,0 +1,603 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== + +# ------------------------------------------------------------------------------ +# Fetches a configuration value from the add-on config file. +# +# Arguments: +# $1 Key of the config option +# ------------------------------------------------------------------------------ +function bashio::config() { + local key=${1} + local query + local result + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + read -r -d '' query << QUERY + if (.${key} == null) then + null + elif (.${key} | type == "string") then + .${key} // empty + elif (.${key} | type == "boolean") then + .${key} // false + elif (.${key} | type == "array") then + if (.${key} == []) then + empty + else + .${key}[] + end + elif (.${key} | type == "object") then + if (.${key} == {}) then + empty + else + .${key} + end + else + .${key} + end +QUERY + + result=$(bashio::jq "${__BASHIO_ADDON_CONFIG}" "${query}") + + if [[ "${result}" == '!secret '* ]]; then + result=$(bashio::secret "${result}") + fi + + printf "%s" "${result}" + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Checks if a configuration option exists in the config file +# +# Arguments: +# $1 Key of the config option +# ------------------------------------------------------------------------------ +function bashio::config.exists() { + local key=${1} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if [[ $(bashio::config ".${key}") != "null" ]]; then + return "${__BASHIO_EXIT_NOK}" + fi + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Checks if a configuration option has an actual value. +# +# Arguments: +# $1 Key of the config option +# ------------------------------------------------------------------------------ +function bashio::config.has_value() { + local key=${1} + local value + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + value=$(bashio::config "${key}") + if [[ "${value}" == "null" ]]; then + return "${__BASHIO_EXIT_NOK}" + fi + + if ! bashio::var.has_value "${value}"; then + return "${__BASHIO_EXIT_NOK}" + fi + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Checks if a configuration option has an empty value. +# +# Arguments: +# $1 Key of the config option +# ------------------------------------------------------------------------------ +function bashio::config.is_empty() { + local key=${1} + local value + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + value=$(bashio::config "${key}") + if bashio::var.is_empty "${value}"; then + return "${__BASHIO_EXIT_OK}" + fi + + if [[ "${value}" == "null" ]]; then + return "${__BASHIO_EXIT_OK}" + fi + + return "${__BASHIO_EXIT_NOK}" +} + +# ------------------------------------------------------------------------------ +# Checks if a configuration option is true. +# +# Arguments: +# $1 Key of the config option +# ------------------------------------------------------------------------------ +function bashio::config.true() { + local key=${1} + local value + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + value=$(bashio::config "${key}") + if ! bashio::var.true "${value}"; then + return "${__BASHIO_EXIT_NOK}" + fi + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Checks if a configuration option is false. +# +# Arguments: +# $1 Key of the config option +# ------------------------------------------------------------------------------ +function bashio::config.false() { + local key=${1} + local value + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + value=$(bashio::config "${key}") + if ! bashio::var.false "${value}"; then + return "${__BASHIO_EXIT_NOK}" + fi + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Checks if a password is safe to use, using IHaveBeenPwned. +# +# Arguments: +# $1 Key of the config option +# ------------------------------------------------------------------------------ +function bashio::config.is_safe_password() { + local key=${1} + local password + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + # If the password is safe, we'll accept it anyways. + password=$(bashio::config "${key}") + if bashio::pwned.is_safe_password "${password}"; then + return "${__BASHIO_EXIT_OK}" + fi + + # If the bypass is enabled, we'll return OK. + if bashio::config.true "i_like_to_be_pwned"; then + bashio::log.warning "Have I Been Pwned bypass enabled." + return "${__BASHIO_EXIT_OK}" + fi + + # If we reach this point, we'll just fail. + return "${__BASHIO_EXIT_NOK}" +} + +# ------------------------------------------------------------------------------ +# Require a configuration option to be set by the user. +# +# Arguments: +# $1 Key of the config option +# $2 Addition reason why this is needed +# ------------------------------------------------------------------------------ +function bashio::config.require() { + local key=${1} + local reason=${2:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if bashio::config.has_value "${key}"; then + return "${__BASHIO_EXIT_OK}" + fi + + bashio::log.fatal + bashio::log.fatal "A required add-on configuration option is missing!" + bashio::log.fatal + bashio::log.fatal "Please set a value for the '${key}' option." + if bashio::var.has_value "${reason}"; then + bashio::log.fatal + bashio::log.fatal "This option is required because:" + bashio::log.fatal "${reason}" + fi + bashio::log.fatal + bashio::log.fatal "If unsure, check the add-on manual for more information." + bashio::log.fatal + + bashio::exit.nok +} + +# ------------------------------------------------------------------------------ +# Suggest on setting a configuration option to the user. +# +# Arguments: +# $1 Key of the config option +# $2 Addition reason why this is needed +# ------------------------------------------------------------------------------ +function bashio::config.suggest() { + local key=${1} + local reason=${2:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if ! bashio::config.has_value "${key}"; then + bashio::log.warning + bashio::log.warning \ + "A recommended add-on configuration option is not set." + bashio::log.warning + bashio::log.warning "The configuration key '${key}' seems to be empty." + bashio::log.warning + if bashio::var.has_value "${reason}"; then + bashio::log.warning + bashio::log.warning "Consider configuring this because:" + bashio::log.warning "${reason}" + fi + bashio::log.warning "Check the add-on manual for more information." + bashio::log.warning + fi + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Suggest on enabling a configuration option to the user. +# +# Arguments: +# $1 Key of the config option +# $2 Addition reason why this is needed +# ------------------------------------------------------------------------------ +function bashio::config.suggest.true() { + local key=${1} + local reason=${2:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if ! bashio::config.true "${key}"; then + bashio::log.warning + bashio::log.warning \ + "A recommended add-on configuration option is not enabled." + if bashio::var.has_value "${reason}"; then + bashio::log.warning + bashio::log.warning "Consider enabling this because:" + bashio::log.warning "${reason}" + fi + bashio::log.warning + bashio::log.warning "Enable config option '${key}' hide this message." + bashio::log.warning + bashio::log.warning "Check the add-on manual for more information." + bashio::log.warning + fi + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Suggest on disabling a configuration option to the user. +# +# Arguments: +# $1 Key of the config option +# $2 Addition reason why this is needed +# ------------------------------------------------------------------------------ +function bashio::config.suggest.false() { + local key=${1} + local reason=${2:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if ! bashio::config.false "${key}"; then + bashio::log.warning + bashio::log.warning \ + "A recommended add-on configuration option is not disabled." + if bashio::var.has_value "${reason}"; then + bashio::log.warning + bashio::log.warning "Consider disabling this because:" + bashio::log.warning "${reason}" + fi + bashio::log.warning + bashio::log.warning "Disable config option '${key}' hide this message." + bashio::log.warning + bashio::log.warning "Check the add-on manual for more information." + bashio::log.warning + fi + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Require the user to configure a username. +# +# Arguments: +# $1 Key of the config option (optional: defaults to 'username') +# ------------------------------------------------------------------------------ +function bashio::config.require.username() { + local key=${1:-"username"} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if bashio::config.has_value "${key}"; then + return "${__BASHIO_EXIT_OK}" + fi + + bashio::log.fatal + bashio::log.fatal "Setting a username is required!" + bashio::log.fatal + bashio::log.fatal "Please username in the '${key}' option." + bashio::log.fatal + bashio::log.fatal "If unsure, check the add-on manual for more information." + bashio::log.fatal + + bashio::exit.nok +} + +# ------------------------------------------------------------------------------ +# Suggest to the user to set a username, in case it is not. +# +# Arguments: +# $1 Key of the config option (optional: defaults to 'username') +# ------------------------------------------------------------------------------ +function bashio::config.suggest.username() { + local key=${1} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if ! bashio::config.has_value "${key}"; then + bashio::log.warning + bashio::log.warning \ + "Setting a username is highly recommended!" + bashio::log.warning + bashio::log.warning "Define a username in the '${key}' option." + bashio::log.warning + bashio::log.warning "Check the add-on manual for more information." + bashio::log.warning + fi + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Checks if the password has been set and exits when it is not. +# +# Arguments: +# $1 Key of the config option (optional: defaults to 'password') +# ------------------------------------------------------------------------------ +function bashio::config.require.password() { + local key=${1:-"password"} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if bashio::config.has_value "${key}"; then + return "${__BASHIO_EXIT_OK}" + fi + + bashio::log.fatal + bashio::log.fatal "Setting a password is required!" + bashio::log.fatal + bashio::log.fatal "Please password in the '${key}' option." + bashio::log.fatal + bashio::log.fatal "If unsure, check the add-on manual for more information." + bashio::log.fatal + + bashio::exit.nok +} + +# ------------------------------------------------------------------------------ +# Suggest to set a password if it was not set. +# +# Arguments: +# $1 Key of the config option (optional: defaults to 'password') +# ------------------------------------------------------------------------------ +function bashio::config.suggest.password() { + local key=${1:-"password"} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if bashio::config.has_value "${key}"; then + return "${__BASHIO_EXIT_OK}" + fi + + bashio::log.warning + bashio::log.warning "Setting a password is highly recommended!" + bashio::log.warning + bashio::log.warning "Please set a password in the '${key}' option." + bashio::log.warning + bashio::log.warning \ + "If unsure, check the add-on manual for more information." + bashio::log.warning + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Require to set a password which is not in HaveIBeenPwned database. +# +# Arguments: +# $1 Key of the config option (optional: defaults to 'password') +# ------------------------------------------------------------------------------ +function bashio::config.require.safe_password() { + local key=${1:-"password"} + local password + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + bashio::config.require.password "${key}" + + password=$(bashio::config "${key}") + + if bashio::pwned.is_safe_password "${password}"; then + return "${__BASHIO_EXIT_OK}" + fi + + bashio::log.fatal + bashio::log.fatal "We are trying to help you to protect your system the" + bashio::log.fatal "best we can. Therefore, this add-on checks your" + bashio::log.fatal "configured password again the HaveIBeenPwned database." + bashio::log.fatal + bashio::log.fatal "Unfortunately, your configured password is considered" + bashio::log.fatal "unsafe. We highly recommend you to pick a different one." + bashio::log.fatal + bashio::log.fatal "Please change the password in the '${key}' option." + bashio::log.fatal + bashio::log.fatal "Check the add-on manual for more information." + bashio::log.fatal + + bashio::exit.nok +} + +# ------------------------------------------------------------------------------ +# Suggest to set a password which is not in HaveIBeenPwned database. +# +# Arguments: +# $1 Key of the config option (optional: defaults to 'password') +# ------------------------------------------------------------------------------ +function bashio::config.suggest.safe_password() { + local key=${1:-"password"} + local password + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if ! bashio::config.has_value "${key}"; then + bashio::config.suggest.password "${key}" + return "${__BASHIO_EXIT_OK}" + fi + + password=$(bashio::config "${key}") + + if bashio::pwned.is_safe_password "${password}"; then + return "${__BASHIO_EXIT_OK}" + fi + + bashio::log.warning + bashio::log.warning "We are trying to help you to protect your system the" + bashio::log.warning "best we can. Therefore, this add-on checks your" + bashio::log.warning "configured password again the HaveIBeenPwned database." + bashio::log.warning + bashio::log.warning "Unfortunately, your configured password is considered" + bashio::log.warning "unsafe. It is recommended to pick a different one." + bashio::log.warning + bashio::log.warning "Please change the password in the '${key}' option." + bashio::log.warning + bashio::log.warning "Check the add-on manual for more information." + bashio::log.warning + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Check if certificate files exists when SSL is enabled. +# +# Arguments: +# $1 Key of the ssl config option (optional: defaults to 'ssl') +# $2 Key of the cert file config option (optional: defaults to 'certfile') +# $3 Key of the cert key file config option (optional: defaults to 'keyfile') +# ------------------------------------------------------------------------------ +function bashio::config.require.ssl() { + local key=${1:-"ssl"} + local certfile=${1:-"certfile"} + local keyfile=${2:-"keyfile"} + + if ! bashio::config.true "${key}"; then + return "${__BASHIO_EXIT_OK}" + fi + + if bashio::config.is_empty "${certfile}"; then + bashio::log.fatal + bashio::log.fatal "SSL has been enabled using the '${key}' option," + bashio::log.fatal "this requires a SSL certificate file which is" + bashio::log.fatal "configured using the '${certfile}' option in the" + bashio::log.fatal "add-on configuration." + bashio::log.fatal + bashio::log.fatal "Unfortunately, the '${certfile}' option is empty." + bashio::log.fatal + bashio::log.fatal "Consider configuring or getting a SSL certificate" + bashio::log.fatal "or setting the '${key}' option to 'false' in case" + bashio::log.fatal "you are not planning on using SSL with this add-on." + bashio::log.fatal + bashio::log.fatal "Check the add-on manual for more information." + bashio::log.fatal + + bashio::exit.nok + fi + + if bashio::config.is_empty "${keyfile}"; then + bashio::log.fatal + bashio::log.fatal "SSL has been enabled using the '${key}' option," + bashio::log.fatal "this requires a SSL certificate key file which is" + bashio::log.fatal "configured using the '${keyfile}' option in the" + bashio::log.fatal "add-on configuration." + bashio::log.fatal + bashio::log.fatal "Unfortunately, the '${keyfile}' option is empty." + bashio::log.fatal + bashio::log.fatal "Consider configuring or getting a SSL certificate" + bashio::log.fatal "or setting the '${key}' option to 'false' in case" + bashio::log.fatal "you are not planning on using SSL with this add-on." + bashio::log.fatal + bashio::log.fatal "Check the add-on manual for more information." + bashio::log.fatal + + bashio::exit.nok + fi + + if ! bashio::fs.file_exists "/ssl/$(bashio::config "${certfile}")"; then + bashio::log.fatal + bashio::log.fatal "SSL has been enabled using the '${key}' option," + bashio::log.fatal "this requires a SSL certificate file which is" + bashio::log.fatal "configured using the '${certfile}' option in the" + bashio::log.fatal "add-on configuration." + bashio::log.fatal + bashio::log.fatal "Unfortunately, the file specified in the" + bashio::log.fatal "'${certfile}' option does not exists." + bashio::log.fatal + bashio::log.fatal "Please ensure the certificate file exists and" + bashio::log.fatal "is placed in the Hass.io '/ssl/' directory." + bashio::log.fatal + bashio::log.fatal "In case you don't have SSL yet, consider getting" + bashio::log.fatal "a SSL certificate or setting the '${key}' option" + bashio::log.fatal "to 'false' in case you are not planning on using" + bashio::log.fatal "SSL with this add-on." + bashio::log.fatal + bashio::log.fatal "Check the add-on manual for more information." + bashio::log.fatal + + bashio::exit.nok + fi + + if ! bashio::fs.file_exists "/ssl/$(bashio::config "${keyfile}")"; then + bashio::log.fatal + bashio::log.fatal "SSL has been enabled using the '${key}' option," + bashio::log.fatal "this requires a SSL certificate key file which is" + bashio::log.fatal "configured using the '${keyfile}' option in the" + bashio::log.fatal "add-on configuration." + bashio::log.fatal + bashio::log.fatal "Unfortunately, the file specified in the" + bashio::log.fatal "'${keyfile}' option does not exists." + bashio::log.fatal + bashio::log.fatal "Please ensure the certificate key file exists and" + bashio::log.fatal "is placed in the Hass.io '/ssl/' directory." + bashio::log.fatal + bashio::log.fatal "In case you don't have SSL yet, consider getting" + bashio::log.fatal "a SSL certificate or setting the '${key}' option" + bashio::log.fatal "to 'false' in case you are not planning on using" + bashio::log.fatal "SSL with this add-on." + bashio::log.fatal + bashio::log.fatal "Check the add-on manual for more information." + bashio::log.fatal + + bashio::exit.nok + fi + + return "${__BASHIO_EXIT_OK}" +} diff --git a/lib/const.sh b/lib/const.sh new file mode 100644 index 0000000..00a9fc5 --- /dev/null +++ b/lib/const.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== + +# Defaults +readonly __BASHIO_DEFAULT_LOG_LEVEL=5 # Defaults to INFO +readonly __BASHIO_DEFAULT_LOG_FORMAT="[{TIMESTAMP}] {LEVEL}: {MESSAGE}" +readonly __BASHIO_DEFAULT_LOG_TIMESTAMP="%T%z" +readonly __BASHIO_DEFAULT_HASSIO_API="http://hassio" +readonly __BASHIO_DEFAULT_HASSIO_TOKEN="" +readonly __BASHIO_DEFAULT_ADDON_CONFIG="/data/options.json" +readonly __BASHIO_DEFAULT_HIBP_ENDPOINT="https://api.pwnedpasswords.com/range" +readonly __BASHIO_DEFAULT_CACHE_DIR="/dev/shm/bashio" +readonly __BASHIO_DEFAULT_SECRETS="/config/secrets.yaml" + +# Exit codes +readonly __BASHIO_EXIT_OK=0 # Successful termination +readonly __BASHIO_EXIT_NOK=1 # Termination with errors + +# Log levels +readonly __BASHIO_LOG_LEVEL_ALL=8 +readonly __BASHIO_LOG_LEVEL_DEBUG=6 +readonly __BASHIO_LOG_LEVEL_ERROR=2 +readonly __BASHIO_LOG_LEVEL_FATAL=1 +readonly __BASHIO_LOG_LEVEL_INFO=5 +readonly __BASHIO_LOG_LEVEL_NOTICE=4 +readonly __BASHIO_LOG_LEVEL_OFF=0 +readonly __BASHIO_LOG_LEVEL_TRACE=7 +readonly __BASHIO_LOG_LEVEL_WARNING=3 +readonly -A __BASHIO_LOG_LEVELS=( + [${__BASHIO_LOG_LEVEL_OFF}]="OFF" + [${__BASHIO_LOG_LEVEL_FATAL}]="FATAL" + [${__BASHIO_LOG_LEVEL_ERROR}]="ERROR" + [${__BASHIO_LOG_LEVEL_WARNING}]="WARNING" + [${__BASHIO_LOG_LEVEL_NOTICE}]="NOTICE" + [${__BASHIO_LOG_LEVEL_INFO}]="INFO" + [${__BASHIO_LOG_LEVEL_DEBUG}]="DEBUG" + [${__BASHIO_LOG_LEVEL_TRACE}]="TRACE" + [${__BASHIO_LOG_LEVEL_ALL}]="ALL" +) + +# Colors +readonly __BASHIO_COLORS_ESCAPE="\033["; +readonly __BASHIO_COLORS_RESET="${__BASHIO_COLORS_ESCAPE}0m" +readonly __BASHIO_COLORS_DEFAULT="${__BASHIO_COLORS_ESCAPE}49m" +readonly __BASHIO_COLORS_BLACK="${__BASHIO_COLORS_ESCAPE}30m" +readonly __BASHIO_COLORS_RED="${__BASHIO_COLORS_ESCAPE}31m" +readonly __BASHIO_COLORS_GREEN="${__BASHIO_COLORS_ESCAPE}32m" +readonly __BASHIO_COLORS_YELLOW="${__BASHIO_COLORS_ESCAPE}33m" +readonly __BASHIO_COLORS_BLUE="${__BASHIO_COLORS_ESCAPE}34m" +readonly __BASHIO_COLORS_MAGENTA="${__BASHIO_COLORS_ESCAPE}35m" +readonly __BASHIO_COLORS_CYAN="${__BASHIO_COLORS_ESCAPE}36m" +readonly __BASHIO_COLORS_LIGHT_GRAY="${__BASHIO_COLORS_ESCAPE}37m" +readonly __BASHIO_COLORS_DARK_GRAY="${__BASHIO_COLORS_ESCAPE}90m" +readonly __BASHIO_COLORS_LIGHT_RED="${__BASHIO_COLORS_ESCAPE}91m" +readonly __BASHIO_COLORS_LIGHT_GREEN="${__BASHIO_COLORS_ESCAPE}92m" +readonly __BASHIO_COLORS_LIGHT_YELLOW="${__BASHIO_COLORS_ESCAPE}93m" +readonly __BASHIO_COLORS_LIGHT_BLUE="${__BASHIO_COLORS_ESCAPE}94m" +readonly __BASHIO_COLORS_LIGHT_MAGENTA="${__BASHIO_COLORS_ESCAPE}95m" +readonly __BASHIO_COLORS_LIGHT_CYAN="${__BASHIO_COLORS_ESCAPE}96m" +readonly __BASHIO_COLORS_WHITE="${__BASHIO_COLORS_ESCAPE}97m" +readonly __BASHIO_COLORS_BG_DEFAULT="${__BASHIO_COLORS_ESCAPE}49m" +readonly __BASHIO_COLORS_BG_BLACK="${__BASHIO_COLORS_ESCAPE}40m" +readonly __BASHIO_COLORS_BG_RED="${__BASHIO_COLORS_ESCAPE}41m" +readonly __BASHIO_COLORS_BG_GREEN="${__BASHIO_COLORS_ESCAPE}42m" +readonly __BASHIO_COLORS_BG_YELLOW="${__BASHIO_COLORS_ESCAPE}43m" +readonly __BASHIO_COLORS_BG_BLUE="${__BASHIO_COLORS_ESCAPE}44m" +readonly __BASHIO_COLORS_BG_MAGENTA="${__BASHIO_COLORS_ESCAPE}45m" +readonly __BASHIO_COLORS_BG_CYAN="${__BASHIO_COLORS_ESCAPE}46m" +readonly __BASHIO_COLORS_BG_LIGHT_GRAY="${__BASHIO_COLORS_ESCAPE}47m" +readonly __BASHIO_COLORS_BG_DARK_GRAY="${__BASHIO_COLORS_ESCAPE}100m" +readonly __BASHIO_COLORS_BG_LIGHT_RED="${__BASHIO_COLORS_ESCAPE}101m" +readonly __BASHIO_COLORS_BG_LIGHT_GREEN="${__BASHIO_COLORS_ESCAPE}102m" +readonly __BASHIO_COLORS_BG_LIGHT_YELLOW="${__BASHIO_COLORS_ESCAPE}103m" +readonly __BASHIO_COLORS_BG_LIGHT_BLUE="${__BASHIO_COLORS_ESCAPE}104m" +readonly __BASHIO_COLORS_BG_LIGHT_MAGENTA="${__BASHIO_COLORS_ESCAPE}105m" +readonly __BASHIO_COLORS_BG_LIGHT_CYAN="${__BASHIO_COLORS_ESCAPE}106m" +readonly __BASHIO_COLORS_BG_LIGHT_WHITE="${__BASHIO_COLORS_ESCAPE}107m" diff --git a/lib/exit.sh b/lib/exit.sh new file mode 100644 index 0000000..f587388 --- /dev/null +++ b/lib/exit.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== + +# ------------------------------------------------------------------------------ +# Exit the script with as failed with an optional error message. +# +# Arguments: +# $1 Error message (optional) +# ------------------------------------------------------------------------------ +function bashio::exit.nok() { + local message=${1:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if bashio::var.has_value "${message}"; then + bashio::log.fatal "${message}" + fi + + exit "${__BASHIO_EXIT_NOK}" +} + +# ------------------------------------------------------------------------------ +# Exit the script when given value is false, with an optional error message. +# +# Arguments: +# $1 Value to check if false +# $2 Error message (optional) +# ------------------------------------------------------------------------------ +function bashio::exit.die_if_false() { + local value=${1:-} + local message=${2:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if bashio::var.false "${value}"; then + bashio::exit.nok "${message}" + fi +} + + +# ------------------------------------------------------------------------------ +# Exit the script when given value is true, with an optional error message. +# +# Arguments: +# $1 Value to check if true +# $2 Error message (optional) +# ------------------------------------------------------------------------------ +function hass.die_if_true() { + local value=${1:-} + local message=${2:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if bashio::var.true "${value}"; then + bashio::exit.nok "${message}" + fi +} + +# ------------------------------------------------------------------------------ +# Exit the script when given value is empty, with an optional error message. +# +# Arguments: +# $1 Value to check if true +# $2 Error message (optional) +# ------------------------------------------------------------------------------ +function hass.die_if_empty() { + local value=${1:-} + local message=${2:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if bashio::var.is_empty "${value}"; then + bashio::exit.nok "${message}" + fi +} + +# ------------------------------------------------------------------------------ +# Exit the script nicely. +# ------------------------------------------------------------------------------ +function bashio::exit.ok() { + bashio::log.trace "${FUNCNAME[0]}" "$@" + exit "${__BASHIO_EXIT_OK}" +} diff --git a/lib/fs.sh b/lib/fs.sh new file mode 100644 index 0000000..ff8372f --- /dev/null +++ b/lib/fs.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== + +# ------------------------------------------------------------------------------ +# Check whether or not a directory exists. +# +# Arguments: +# $1 Path to directory +# ------------------------------------------------------------------------------ +function bashio::fs.directory_exists() { + local directory=${1} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if [[ -d "${directory}" ]]; then + return "${__BASHIO_EXIT_OK}" + fi + + return "${__BASHIO_EXIT_NOK}" +} + +# ------------------------------------------------------------------------------ +# Check whether or not a file exists. +# +# Arguments: +# $1 Path to file +# ------------------------------------------------------------------------------ +function bashio::fs.file_exists() { + local file=${1} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if [[ -f "${file}" ]]; then + return "${__BASHIO_EXIT_OK}" + fi + + return "${__BASHIO_EXIT_NOK}" +} + +# ------------------------------------------------------------------------------ +# Check whether or not a device exists. +# +# Arguments: +# $1 Path to device +# ------------------------------------------------------------------------------ +function bashio::fs.device_exists() { + local device=${1} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if [[ -d "${device}" ]]; then + return "${__BASHIO_EXIT_OK}" + fi + + return "${__BASHIO_EXIT_NOK}" +} + +# ------------------------------------------------------------------------------ +# Check whether or not a socket exists. +# +# Arguments: +# $1 Path to socket +# ------------------------------------------------------------------------------ +function bashio::fs.socket_exists() { + local socket=${1} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if [[ -S "${socket}" ]]; then + return "${__BASHIO_EXIT_OK}" + fi + + return "${__BASHIO_EXIT_NOK}" +} diff --git a/lib/hardware.sh b/lib/hardware.sh new file mode 100644 index 0000000..a68ba13 --- /dev/null +++ b/lib/hardware.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== + +# ------------------------------------------------------------------------------ +# Returns a JSON object with hardware information about the system. +# +# Arguments: +# $1 Cache key to store results in (optional) +# $2 jq Filter to apply on the result (optional) +# ------------------------------------------------------------------------------ +function bashio::hardware() { + local cache_key=${1:-'hardware.info'} + local filter=${2:-} + local info + local response + + bashio::log.trace "${FUNCNAME[0]}" "$@" + + if bashio::cache.exists "${cache_key}"; then + bashio::cache.get "${cache_key}" + return "${__BASHIO_EXIT_OK}" + fi + + if bashio::cache.exists 'hardware.info'; then + info=$(bashio::cache.get 'hardware.info') + else + info=$(bashio::api.hassio GET /hardware/info false) + bashio::cache.set 'hardware.info' "${info}" + fi + + response="${info}" + if bashio::var.has_value "${filter}"; then + response=$(bashio::jq "${info}" "${filter}") + fi + + bashio::cache.set "${cache_key}" "${response}" + printf "%s" "${response}" + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Returns a list of available serial devices on the host system. +# ------------------------------------------------------------------------------ +function bashio::hardware.serial() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::hardware 'hardware.info.serial' '.serial[]' +} + +# ------------------------------------------------------------------------------ +# Returns a list of available input devices on the host system. +# ------------------------------------------------------------------------------ +function bashio::hardware.input() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::hardware 'hardware.info.input' '.input[]' +} + +# ------------------------------------------------------------------------------ +# Returns a list of available disk devices on the host system. +# ------------------------------------------------------------------------------ +function bashio::hardware.disk() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::hardware 'hardware.info.disk' '.disk[]' +} + +# ------------------------------------------------------------------------------ +# Returns a list of available GPIO on the host system. +# ------------------------------------------------------------------------------ +function bashio::hardware.gpio() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::hardware 'hardware.info.gpio' '.gpio[]' +} diff --git a/lib/hassos.sh b/lib/hassos.sh new file mode 100644 index 0000000..993f9cc --- /dev/null +++ b/lib/hassos.sh @@ -0,0 +1,172 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== + +# ------------------------------------------------------------------------------ +# Updates HassOS to the latest version. +# +# Arguments: +# $1 Version to update to (optional) +# ------------------------------------------------------------------------------ +function bashio::hassos.update() { + local version=${1:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if bashio::var.has_value "${version}"; then + version=$(bashio::var.json version "${version}") + bashio::api.hassio POST /hassos/update "${version}" + else + bashio::api.hassio POST /hassos/update + fi + bashio::cache.flush_all +} + +# ------------------------------------------------------------------------------ +# Updates HassOS CLI to the latest version. +# +# Arguments: +# $1 Version to update to (optional) +# ------------------------------------------------------------------------------ +function bashio::hassos.update_cli() { + local version=${1:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if bashio::var.has_value "${version}"; then + version=$(bashio::var.json version "${version}") + bashio::api.hassio POST /hassos/update/cli "${version}" + else + bashio::api.hassio POST /hassos/update/cli + fi + bashio::cache.flush_all +} + +# ------------------------------------------------------------------------------ +# Load HassOS host configuration from USB stick. +# ------------------------------------------------------------------------------ +function bashio::hassos.config_sync() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio POST /hassos/config/sync +} + +# ------------------------------------------------------------------------------ +# Returns a JSON object with generic Home Asssistant information. +# +# Arguments: +# $1 Cache key to store results in (optional) +# $2 jq Filter to apply on the result (optional) +# ------------------------------------------------------------------------------ +function bashio::hassos() { + local cache_key=${1:-'hassos.info'} + local filter=${2:-} + local info + local response + + bashio::log.trace "${FUNCNAME[0]}" "$@" + + if bashio::cache.exists "${cache_key}"; then + bashio::cache.get "${cache_key}" + return "${__BASHIO_EXIT_OK}" + fi + + if bashio::cache.exists 'hassos.info'; then + info=$(bashio::cache.get 'hassio.hassos') + else + info=$(bashio::api.hassio GET /hassos/info false) + bashio::cache.set 'hassos.info' "${info}" + fi + + response="${info}" + if bashio::var.has_value "${filter}"; then + response=$(bashio::jq "${info}" "${filter}") + fi + + bashio::cache.set "${cache_key}" "${response}" + printf "%s" "${response}" + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Returns the version of HassOS. +# ------------------------------------------------------------------------------ +function bashio::hassos.version() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::hassos 'hassos.info.version' '.version' +} + +# ------------------------------------------------------------------------------ +# Returns the latest version of HassOS. +# ------------------------------------------------------------------------------ +function bashio::hassos.version_latest() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::hassos 'hassos.info.version_latest' '.version_latest' +} + +# ------------------------------------------------------------------------------ +# Checks if there is an update available for the Supervisor. +# ------------------------------------------------------------------------------ +function bashio::hassos.update_available() { + local version + local last_version + + bashio::log.trace "${FUNCNAME[0]}" + + version=$(bashio::hassos.version) + last_version=$(bashio::hassos.last_version) + + if [[ "${version}" = "${last_version}" ]]; then + return "${__BASHIO_EXIT_NOK}" + fi + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Returns the CLI version of HassOS. +# ------------------------------------------------------------------------------ +function bashio::hassos.version_cli() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::hassos 'hassos.info.version_cli' '.version_cli' +} + +# ------------------------------------------------------------------------------ +# Returns the latest CLI version of HassOS. +# ------------------------------------------------------------------------------ +function bashio::hassos.version_cli_latest() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::hassos 'hassos.info.version_cli_latest' '.version_cli_latest' +} + +# ------------------------------------------------------------------------------ +# Checks if there is an update available for the Supervisor. +# ------------------------------------------------------------------------------ +function bashio::hassos.update_available_cli() { + local version + local last_version + + bashio::log.trace "${FUNCNAME[0]}" + + version=$(bashio::hassos.version_cli) + last_version=$(bashio::hassos.version_cli_latest) + + if [[ "${version}" = "${last_version}" ]]; then + return "${__BASHIO_EXIT_NOK}" + fi + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Returns the board running HassOS. +# ------------------------------------------------------------------------------ +function bashio::hassos.board() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::hassos 'hassos.info.board' '.board' +} diff --git a/lib/homeassistant.sh b/lib/homeassistant.sh new file mode 100644 index 0000000..ae1aa95 --- /dev/null +++ b/lib/homeassistant.sh @@ -0,0 +1,323 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== + +# ------------------------------------------------------------------------------ +# Starts Home Assistant. +# ------------------------------------------------------------------------------ +function bashio::homeassistant.start() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio POST /homeassistant/start +} + +# ------------------------------------------------------------------------------ +# Stops Home Assistant. +# ------------------------------------------------------------------------------ +function bashio::homeassistant.stop() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio POST /homeassistant/stop +} + +# ------------------------------------------------------------------------------ +# Restarts Home Assistant. +# ------------------------------------------------------------------------------ +function bashio::homeassistant.restart() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio POST /homeassistant/restart +} + +# ------------------------------------------------------------------------------ +# Updates Home Assistant to the latest version. +# +# Arguments: +# $1 Version to update to (optional) +# ------------------------------------------------------------------------------ +function bashio::homeassistant.update() { + local version=${1:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if bashio::var.has_value "${version}"; then + version=$(bashio::var.json version "${version}") + bashio::api.hassio POST /homeassistant/update "${version}" + else + bashio::api.hassio POST /homeassistant/update + fi + bashio::cache.flush_all +} + +# ------------------------------------------------------------------------------ +# Checks/validates your Home Assistant configuration. +# ------------------------------------------------------------------------------ +function bashio::homeassistant.check() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio POST /homeassistant/check +} + +# ------------------------------------------------------------------------------ +# Returns the logs created by Home Assistant. +# ------------------------------------------------------------------------------ +function bashio::homeassistant.logs() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio GET /homeassistant/logs true +} + +# ------------------------------------------------------------------------------ +# Returns a JSON object with generic Home Asssistant information. +# +# Arguments: +# $1 Cache key to store results in (optional) +# $2 jq Filter to apply on the result (optional) +# ------------------------------------------------------------------------------ +function bashio::homeassistant() { + local cache_key=${1:-'homeassistant.info'} + local filter=${2:-} + local info + local response + + bashio::log.trace "${FUNCNAME[0]}" "$@" + + if bashio::cache.exists "${cache_key}"; then + bashio::cache.get "${cache_key}" + return "${__BASHIO_EXIT_OK}" + fi + + if bashio::cache.exists 'homeassistant.info'; then + info=$(bashio::cache.get 'hassio.homeassistant') + else + info=$(bashio::api.hassio GET /homeassistant/info false) + bashio::cache.set 'homeassistant.info' "${info}" + fi + + response="${info}" + if bashio::var.has_value "${filter}"; then + response=$(bashio::jq "${info}" "${filter}") + fi + + bashio::cache.set "${cache_key}" "${response}" + printf "%s" "${response}" + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Returns the version of Home Assistant. +# ------------------------------------------------------------------------------ +function bashio::homeassistant.version() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::homeassistant 'homeassistant.info.version' '.version' +} + +# ------------------------------------------------------------------------------ +# Returns the latest version of Home Assistant. +# ------------------------------------------------------------------------------ +function bashio::homeassistant.last_version() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::homeassistant 'homeassistant.info.last_version' '.last_version' +} + +# ------------------------------------------------------------------------------ +# Checks if there is an update available for the Supervisor. +# ------------------------------------------------------------------------------ +function bashio::supervisor.update_available() { + local version + local last_version + + bashio::log.trace "${FUNCNAME[0]}" + + version=$(bashio::homeassistant.version) + last_version=$(bashio::homeassistant.last_version) + + if [[ "${version}" = "${last_version}" ]]; then + return "${__BASHIO_EXIT_NOK}" + fi + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Returns the arch of Home Assistant. +# ------------------------------------------------------------------------------ +function bashio::homeassistant.arch() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::homeassistant 'homeassistant.info.arch' '.arch' +} + +# ------------------------------------------------------------------------------ +# Returns the machine info running Home Assistant. +# ------------------------------------------------------------------------------ +function bashio::homeassistant.machine() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::homeassistant 'homeassistant.info.machine' '.machine' +} + +# ------------------------------------------------------------------------------ +# Returns the Docker image of Home Assistant. +# +# Arguments: +# $1 Image to set (optional). +# ------------------------------------------------------------------------------ +function bashio::homeassistant.image() { + local image=${1:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if bashio::var.has_value "${image}"; then + image=$(bashio::var.json image "${image}") + bashio::api.hassio POST /homeassistant/options "${image}" + bashio::cache.flush_all + else + bashio::homeassistant 'homeassistant.info.image' '.image' + fi +} + +# ------------------------------------------------------------------------------ +# Returns whether or not a custom version of Home Assistant is installed. +# ------------------------------------------------------------------------------ +function bashio::homeassistant.custom() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::homeassistant 'homeassistant.info.custom' '.custom // false' +} + +# ------------------------------------------------------------------------------ +# Returns whether or not Home Assistant starts at device boot. +# ------------------------------------------------------------------------------ +function bashio::homeassistant.boot() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::homeassistant 'homeassistant.info.boot' '.boot // false' + +# ------------------------------------------------------------------------------ +} +# Returns the port number on which Home Assistant is running. +# ------------------------------------------------------------------------------ +function bashio::homeassistant.port() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::homeassistant 'homeassistant.port' '.port' +} + +# ------------------------------------------------------------------------------ +# Returns whether or not Home Assistant is running on SSL. +# ------------------------------------------------------------------------------ +function bashio::homeassistant.ssl() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::homeassistant 'homeassistant.info.ssl' '.ssl // false' +} + +# ------------------------------------------------------------------------------ +# Returns or sets whether or not Home Assistant is monitored by Watchdog. +# +# Arguments: +# $1 True to enable watchdog, false otherwise (optional). +# ------------------------------------------------------------------------------ +function bashio::homeassistant.watchdog() { + local watchdog=${1:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if bashio::var.has_value "${wait}"; then + watchdog=$(bashio::var.json watchdog "^${watchdog}") + bashio::api.hassio POST /homeassistant/options "${watchdog}" + bashio::cache.flush_all + else + bashio::homeassistant 'homeassistant.info.watchdog' '.watchdog // false' + fi +} + +# ------------------------------------------------------------------------------ +# List all available stats about Home Assistant. +# +# Arguments: +# $1 Cache key to store results in (optional) +# $2 jq Filter to apply on the result (optional) +# ------------------------------------------------------------------------------ +function bashio::homeassistant.stats() { + local cache_key=${1:-'homeassistant.stats'} + local filter=${2:-} + local info + local response + + bashio::log.trace "${FUNCNAME[0]}" "$@" + + if bashio::cache.exists "${cache_key}"; then + bashio::cache.get "${cache_key}" + return "${__BASHIO_EXIT_OK}" + fi + + if bashio::cache.exists 'homeassistant.stats'; then + info=$(bashio::cache.get 'homeassistant.stats') + else + info=$(bashio::api.hassio GET /homeassistant/stats false) + bashio::cache.set 'homeassistant.stats' "${info}" + fi + + response="${info}" + if bashio::var.has_value "${filter}"; then + response=$(bashio::jq "${info}" "${filter}") + fi + + bashio::cache.set "${cache_key}" "${response}" + printf "%s" "${response}" + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Returns CPU usage from Home Assistant. +# ------------------------------------------------------------------------------ +function bashio::homeassistant.cpu_percent() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::homeassistant.stats 'homeassistant.stats.cpu_percent' '.cpu_percent' +} + +# ------------------------------------------------------------------------------ +# Returns memory usage from Home Assistant. +# ------------------------------------------------------------------------------ +function bashio::homeassistant.memory_usage() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::homeassistant.stats 'homeassistant.stats.memory_usage' '.memory_usage' +} + +# ------------------------------------------------------------------------------ +# Returns memory limit from Home Assistant. +# ------------------------------------------------------------------------------ +function bashio::homeassistant.memory_limit() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::homeassistant.stats 'homeassistant.stats.memory_limit' '.memory_limit' +} + +# ------------------------------------------------------------------------------ +# Returns outgoing network usage from Home Assistant. +# ------------------------------------------------------------------------------ +function bashio::homeassistant.network_tx() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::homeassistant.stats 'homeassistant.stats.network_tx' '.network_tx' +} + +# ------------------------------------------------------------------------------ +# Returns incoming network usage from Home Assistant. +# ------------------------------------------------------------------------------ +function bashio::homeassistant.network_rx() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::homeassistant.stats 'homeassistant.stats.network_rx' '.network_rx' +} + +# ------------------------------------------------------------------------------ +# Returns disk read usage from Home Assistant. +# ------------------------------------------------------------------------------ +function bashio::homeassistant.blk_read() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::homeassistant.stats 'homeassistant.stats.blk_read' '.blk_read' +} + +# ------------------------------------------------------------------------------ +# Returns disk write usage from Home Assistant. +# ------------------------------------------------------------------------------ +function bashio::homeassistant.blk_write() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::homeassistant.stats 'homeassistant.stats.blk_write' '.blk_write' +} diff --git a/lib/host.sh b/lib/host.sh new file mode 100644 index 0000000..53545fc --- /dev/null +++ b/lib/host.sh @@ -0,0 +1,135 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== + +# ------------------------------------------------------------------------------ +# Reload the host controller. +# ------------------------------------------------------------------------------ +function bashio::host.reload() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio POST /host/reload +} + +# ------------------------------------------------------------------------------ +# Shuts down the host system. +# ------------------------------------------------------------------------------ +function bashio::host.shutdown() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio POST /host/shutdown +} + +# ------------------------------------------------------------------------------ +# Reboots the host system. +# ------------------------------------------------------------------------------ +function bashio::host.reboot() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio POST /host/reboot +} + +# ------------------------------------------------------------------------------ +# Returns a JSON object with generic Host information. +# +# Arguments: +# $1 Cache key to store results in (optional) +# $2 jq Filter to apply on the result (optional) +# ------------------------------------------------------------------------------ +function bashio::host() { + local cache_key=${1:-'host.info'} + local filter=${2:-} + local info + local response + + bashio::log.trace "${FUNCNAME[0]}" "$@" + + if bashio::cache.exists "${cache_key}"; then + bashio::cache.get "${cache_key}" + return "${__BASHIO_EXIT_OK}" + fi + + if bashio::cache.exists 'host.info'; then + info=$(bashio::cache.get 'host.info') + else + info=$(bashio::api.hassio GET /host/info false) + bashio::cache.set 'host.info' "${info}" + fi + + response="${info}" + if bashio::var.has_value "${filter}"; then + response=$(bashio::jq "${info}" "${filter}") + fi + + bashio::cache.set "${cache_key}" "${response}" + printf "%s" "${response}" + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Returns the hostname of the host system. +# ------------------------------------------------------------------------------ +function bashio::host.hostname() { + local hostname=${1:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if bashio::var.has_value "${hostname}"; then + hostname=$(bashio::var.json hostname "${hostname}") + bashio::api.hassio POST /host/options "${hostname}" + bashio::cache.flush_all + else + bashio::host 'host.info.hostname' '.hostname' + fi +} + +# ------------------------------------------------------------------------------ +# Returns a list of exposed features by the host. +# ------------------------------------------------------------------------------ +function bashio::host.features() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::host 'host.info.features' '.features[]' +} + +# ------------------------------------------------------------------------------ +# Returns the OS of the host system. +# ------------------------------------------------------------------------------ +function bashio::host.operating_system() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::host 'host.info.operating_system' '.operating_system' +} + +# ------------------------------------------------------------------------------ +# Returns the kernel of the host system. +# ------------------------------------------------------------------------------ +function bashio::host.kernel() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::host 'host.info.kernel' '.kernel' +} + +# ------------------------------------------------------------------------------ +# Returns the chassis of the host system. +# ------------------------------------------------------------------------------ +function bashio::host.chassis() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::host 'host.info.chassis' '.chassis' +} + +# ------------------------------------------------------------------------------ +# Returns the stability channel / deployment of the system. +# ------------------------------------------------------------------------------ +function bashio::host.deployment() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::host 'host.info.deployment' '.deployment' +} + +# ------------------------------------------------------------------------------ +# Returns the cpe from the host. +# ------------------------------------------------------------------------------ +function bashio::host.cpe() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::host 'host.info.cpe' '.cpe' +} diff --git a/lib/info.sh b/lib/info.sh new file mode 100644 index 0000000..9107fb9 --- /dev/null +++ b/lib/info.sh @@ -0,0 +1,110 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== + +# ------------------------------------------------------------------------------ +# Returns a JSON object with generic version information about the system. +# +# Arguments: +# $1 Cache key to store results in (optional) +# $2 jq Filter to apply on the result (optional) +# ------------------------------------------------------------------------------ +function bashio::info() { + local cache_key=${1:-'hassio.info'} + local filter=${2:-} + local info + local response + + bashio::log.trace "${FUNCNAME[0]}" "$@" + + if bashio::cache.exists "${cache_key}"; then + bashio::cache.get "${cache_key}" + return "${__BASHIO_EXIT_OK}" + fi + + if bashio::cache.exists 'hassio.info'; then + info=$(bashio::cache.get 'hassio.info') + else + info=$(bashio::api.hassio GET /info false) + bashio::cache.set 'hassio.info' "${info}" + fi + + response="${info}" + if bashio::var.has_value "${filter}"; then + response=$(bashio::jq "${info}" "${filter}") + fi + + bashio::cache.set "${cache_key}" "${response}" + printf "%s" "${response}" + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Returns the Hass.io supervisor version used. +# ------------------------------------------------------------------------------ +function bashio::info.supervisor() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::hassio::info 'hassio.info.supervisor' '.supervisor' +} + +# ------------------------------------------------------------------------------ +# Returns the Home Assistant version used. +# ------------------------------------------------------------------------------ +function bashio::info.homeassistant() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::info 'hassio.info.homeassistant' '.homeassistant' +} + +# ------------------------------------------------------------------------------ +# Returns the hassos version running on the host system. +# ------------------------------------------------------------------------------ +function bashio::info.hassos() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::info 'hassio.info.hassos' '.hassos' +} + +# ------------------------------------------------------------------------------ +# Returns the hostname of the host system. +# ------------------------------------------------------------------------------ +function bashio::info.hostname() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::info 'hassio.info.hostname' '.hostname' +} + +# ------------------------------------------------------------------------------ +# Returns the machine type used. +# ------------------------------------------------------------------------------ +function bashio::info.machine() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::info 'hassio.info.machine' '.machine' +} + +# ------------------------------------------------------------------------------ +# Returns the architecture of the machine. +# ------------------------------------------------------------------------------ +function bashio::info.arch() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::info 'hassio.info.arch' '.arch' +} + +# ------------------------------------------------------------------------------ +# Returns the stability channel the system is enrolled in. +# ------------------------------------------------------------------------------ +function bashio::info.channel() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::info 'hassio.info.channel' '.channel' +} + +# ------------------------------------------------------------------------------ +# Returns a list of supported architectures by this system. +# ------------------------------------------------------------------------------ +function bashio::info.supported_arch() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::info 'hassio.info.supported_arch' '.supported_arch[]' +} diff --git a/lib/jq.sh b/lib/jq.sh new file mode 100644 index 0000000..0950e56 --- /dev/null +++ b/lib/jq.sh @@ -0,0 +1,173 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== + +# ------------------------------------------------------------------------------ +# Execute a JSON query. +# +# Arguments: +# $1 JSON string or path to a JSON file +# $2 jq filter (optional) +# ------------------------------------------------------------------------------ +function bashio::jq() { + local data=${1} + local filter=${2:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if [[ -f "${data}" ]]; then + jq --raw-output -c -M "$filter" "${data}" + else + jq --raw-output -c -M "$filter" <<< "${data}" + fi +} + +# ------------------------------------------------------------------------------ +# Checks if variable exists (optionally after filtering). +# +# Arguments: +# $1 JSON string or path to a JSON file +# $2 jq filter (optional) +# ------------------------------------------------------------------------------ +function bashio::jq.exists() { + local data=${1} + local filter=${2:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if [[ $(bashio::jq "${data}" "${filter}") = "null" ]]; then + return "${__BASHIO_EXIT_NOK}" + fi + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Checks if data exists (optionally after filtering). +# +# Arguments: +# $1 JSON string or path to a JSON file +# $2 jq filter (optional) +# ------------------------------------------------------------------------------ +function bashio::jq.has_value() { + local data=${1} + local filter=${2:-} + local value + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + value=$(bashio::jq "${data}" \ + "${filter} | if (. == {} or . == []) then empty else . end // empty") + + if ! hass.has_value "${value}"; then + return "${__BASHIO_EXIT_NOK}" + fi + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Checks if resulting data is of a specific type. +# +# Arguments: +# $1 JSON string or path to a JSON file +# $2 jq filter +# $3 type (boolean, string, number, array, object, null) +# ------------------------------------------------------------------------------ +function bashio::jq.is() { + local data=${1} + local filter=${2} + local type=${3} + local value + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + value=$(bashio::jq "${data}" \ + "${filter} | if type==\"${type}\" then true else false end") + + if [[ "${value}" = "false" ]]; then + return "${__BASHIO_EXIT_NOK}" + fi + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Checks if resulting data is a boolean. +# +# Arguments: +# $1 JSON string or path to a JSON file +# $2 jq filter (optional) +# ------------------------------------------------------------------------------ +function bashio::jq.is_boolean() { + local data=${1} + local filter=${2:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + bashio::jq.is "${data}" "${filter}" "boolean" +} + +# ------------------------------------------------------------------------------ +# Checks if resulting data is a string. +# +# Arguments: +# $1 JSON string or path to a JSON file +# $2 jq filter (optional) +# ------------------------------------------------------------------------------ +function bashio::jq.is_string() { + local data=${1} + local filter=${2:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + bashio::jq.is "${data}" "${filter}" "string" +} + +# ------------------------------------------------------------------------------ +# Checks if resulting data is an object. +# +# Arguments: +# $1 JSON string or path to a JSON file +# $2 jq filter (optional) +# ------------------------------------------------------------------------------ +function bashio::jq.is_object() { + local data=${1} + local filter=${2:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + bashio::jq.is "${data}" "${filter}" "object" +} + +# ------------------------------------------------------------------------------ +# Checks if resulting data is a number. +# +# Arguments: +# $1 JSON string or path to a JSON file +# $2 jq filter (optional) +# ------------------------------------------------------------------------------ +function bashio::jq.is_number() { + local data=${1} + local filter=${2:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + bashio::jq.is "${data}" "${filter}" "number" +} + +# ------------------------------------------------------------------------------ +# Checks if resulting data is an array. +# +# Arguments: +# $1 JSON string or path to a JSON file +# $2 jq filter (optional) +# ------------------------------------------------------------------------------ +function bashio::jq.is_array() { + local data=${1} + local filter=${2:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + bashio::jq.is "${data}" "${filter}" "array" +} diff --git a/lib/log.sh b/lib/log.sh new file mode 100644 index 0000000..3b9fae0 --- /dev/null +++ b/lib/log.sh @@ -0,0 +1,128 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== + +# ------------------------------------------------------------------------------ +# Log a message +# +# Arguments: +# $1 Log level +# $2 Message to display +# ------------------------------------------------------------------------------ +function bashio::log.log() { + local level=${1} + local message=${2} + local timestamp + local output + + if [[ "${level}" -gt "${__BASHIO_LOG_LEVEL}" ]]; then + return "${__BASHIO_EXIT_OK}" + fi + + timestamp=$(date +"${__BASHIO_LOG_TIMESTAMP}") + + output="${__BASHIO_LOG_FORMAT}" + output="${output//\{TIMESTAMP\}/${timestamp}}" + output="${output//\{MESSAGE\}/${message}}" + output="${output//\{LEVEL\}/${__BASHIO_LOG_LEVELS[$level]}}" + + echo "${output}" >&2 + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Log a message @ trace level +# +# Arguments: +# $* Message to display +# ------------------------------------------------------------------------------ +function bashio::log.trace() { + local message=$* + bashio::color.dark_grey >&2 + bashio::log.log "${__BASHIO_LOG_LEVEL_TRACE}" "${message}" + bashio::color.reset >&2 +} + +# ------------------------------------------------------------------------------ +# Log a message @ debug level. +# +# Arguments: +# $* Message to display +# ------------------------------------------------------------------------------ +function bashio::log.debug() { + local message=$* + bashio::color.dark_grey >&2 + bashio::log.log "${__BASHIO_LOG_LEVEL_DEBUG}" "${message}" + bashio::color.reset >&2 +} + +# ------------------------------------------------------------------------------ +# Log a message @ info level +# +# Arguments: +# $* Message to display +# ------------------------------------------------------------------------------ +function bashio::log.info() { + local message=$* + bashio::color.light_blue >&2 + bashio::log.log "${__BASHIO_LOG_LEVEL_INFO}" "${message}" + bashio::color.reset >&2 +} + +# ------------------------------------------------------------------------------ +# Log a message @ notice level. +# +# Arguments: +# $* Message to display +# ------------------------------------------------------------------------------ +function bashio::log.notice() { + local message=$* + bashio::color.cyan >&2 + bashio::log.log "${__BASHIO_LOG_LEVEL_NOTICE}" "${message}" + bashio::color.reset >&2 +} + +# ------------------------------------------------------------------------------ +# Log a message @ warning level. +# +# Arguments: +# $* Message to display +# ------------------------------------------------------------------------------ +function bashio::log.warning() { + local message=$* + bashio::color.yellow >&2 + bashio::log.log "${__BASHIO_LOG_LEVEL_WARNING}" "${message}" + bashio::color.reset >&2 +} + +# ------------------------------------------------------------------------------ +# Log a message @ error level. +# +# Arguments: +# $* Message to display +# ------------------------------------------------------------------------------ +function bashio::log.error() { + local message=$* + bashio::color.magenta >&2 + bashio::log.log "${__BASHIO_LOG_LEVEL_ERROR}" "${message}" + bashio::color.reset >&2 +} + +# ------------------------------------------------------------------------------ +# Log a message @ fatal level. +# +# Arguments: +# $* Message to display +# ------------------------------------------------------------------------------ +function bashio::log.fatal() { + local message=$* + bashio::color.red >&2 + bashio::log.log "${__BASHIO_LOG_LEVEL_FATAL}" "${message}" + bashio::color.reset >&2 +} diff --git a/lib/pwned.sh b/lib/pwned.sh new file mode 100644 index 0000000..669718a --- /dev/null +++ b/lib/pwned.sh @@ -0,0 +1,140 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== + +# ------------------------------------------------------------------------------ +# Checks if a given password is safe to use. +# +# Arguments: +# $1 The password to check +# ------------------------------------------------------------------------------ +function bashio::pwned.is_safe_password() { + local password="${1}" + local occurances + + bashio::log.trace "${FUNCNAME[0]}" "" + + if ! occurances=$(bashio::pwned "${password}"); then + bashio::log.warning "Could not check password, assuming it is safe." + return "${__BASHIO_EXIT_OK}" + fi + + if [[ "${occurances}" -ne 0 ]]; then + return "${__BASHIO_EXIT_NOK}" + fi + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Gets the number of occurances of the password in the list. +# +# Arguments: +# $1 The password to check +# ------------------------------------------------------------------------------ +function bashio::pwned.occurances() { + local password="${1}" + local occurances + + bashio::log.trace "${FUNCNAME[0]}" "" + + if ! occurances=$(bashio::pwned "${password}"); then + occurances="0" + fi + + echo -n "${occurances}" + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Makes a call to the Have I Been Pwned password database +# +# Arguments: +# $1 The password to check +# ------------------------------------------------------------------------------ +function bashio::pwned() { + local password="${1}" + local response + local status + local hibp_hash + local count + + bashio::log.trace "${FUNCNAME[0]}" "${password//./x}" + + # Do not check empty password + if ! bashio::var.has_value "${password}"; then + bashio::log.warning 'Cannot check empty password against HaveIBeenPwned.' + return "${__BASHIO_EXIT_NOK}" + fi + + # Hash the password + password=$(echo -n "${password}" \ + | sha1sum \ + | tr '[:lower:]' '[:upper:]' \ + | awk -F' ' '{ print $1 }' + ) + bashio::log.debug "Password SHA1: ${password}" + + # Check with have I Been Powned, only send the first 5 chars of the hash + if ! response=$(curl \ + --silent \ + --show-error \ + --write-out '\n%{http_code}' \ + --request GET \ + "${__BASHIO_HIBP_ENDPOINT}/${password:0:5}" + ); then + bashio::log.debug "${response}" + bashio::log.error "Something went wrong contacting the HIBP API" + return "${__BASHIO_EXIT_NOK}" + fi + + status=${response##*$'\n'} + response=${response%$status} + + bashio::log.debug "Requested API resource: ${__BASHIO_HIBP_ENDPOINT}/${password:0:5}" + bashio::log.debug "API HTTP Response code: ${status}" + bashio::log.trace "API Response: ${response}" + + if [[ "${status}" -eq 429 ]]; then + bashio::log.error "HIBP Rate limit exceeded." + return "${__BASHIO_EXIT_NOK}" + fi + + if [[ "${status}" -eq 503 ]]; then + bashio::log.error "HIBP Service unavailable." + return "${__BASHIO_EXIT_NOK}" + fi + + if [[ "${status}" -ne 200 ]]; then + bashio::log.error "Unknown HIBP HTTP error occured." + return "${__BASHIO_EXIT_NOK}" + fi + + # Check the list of returned hashes for a match + for hibp_hash in ${response}; do + if [[ "${password:5:35}" == "${hibp_hash%%:*}" ]]; then + # Found a match! This is bad :( + count=$(echo "${hibp_hash#*:}" | tr -d '\r') + + bashio::log.warning \ + "Password is in the Have I Been Pwned database!" + bashio::log.warning \ + "Password appeared ${count} times!" + echo "${count}" + + # Well, at least the execution of this function succeeded. + return "${__BASHIO_EXIT_OK}" + fi + done + + # Password was not found + echo "0" + bashio::log.info "Password is NOT in the Have I Been Pwned database! Nice!" + + return "${__BASHIO_EXIT_OK}" +} diff --git a/lib/repositories.sh b/lib/repositories.sh new file mode 100644 index 0000000..8d353fb --- /dev/null +++ b/lib/repositories.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== + +# ------------------------------------------------------------------------------ +# Returns a JSON object with generic version information about repositories. +# +# Arguments: +# $1 Add-on slug (optional) +# $1 Cache key to store results in (optional) +# $2 jq Filter to apply on the result (optional) +# ------------------------------------------------------------------------------ +function bashio::repositories() { + local slug=${1:-false} + local cache_key=${2:-'repositories.list'} + local filter=${3:-'.repositories[].slug'} + local info + local response + + bashio::log.trace "${FUNCNAME[0]}" "$@" + + if bashio::cache.exists "${cache_key}"; then + bashio::cache.get "${cache_key}" + return "${__BASHIO_EXIT_OK}" + fi + + if bashio::var.false "${slug}"; then + if bashio::cache.exists "repositories.list"; then + info=$(bashio::cache.get 'repositories.list') + else + info=$(bashio::api.hassio GET "/addons" false) + bashio::cache.set "repositories.list" "${info}" + fi + else + if bashio::cache.exists "repositories.${slug}.info"; then + info=$(bashio::cache.get "repositories.${slug}.info") + else + info=$(bashio::api.hassio GET "/addons" \ + false ".repositories[] | select(.slug==\"${slug}\")") + bashio::cache.set "repositories.${slug}.info" "${info}" + fi + fi + + response="${info}" + if bashio::var.has_value "${filter}"; then + response=$(bashio::jq "${info}" "${filter}") + fi + + bashio::cache.set "${cache_key}" "${response}" + printf "%s" "${response}" + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Returns the name of a repository. +# +# Arguments: +# $1 Repository slug +# ------------------------------------------------------------------------------ +function bashio::repository.name() { + local slug=${1} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::repositories "${slug}" "repositories.${slug}.name" '.name' +} + +# ------------------------------------------------------------------------------ +# Returns the source of a repository. +# +# Arguments: +# $1 Repository slug +# ------------------------------------------------------------------------------ +function bashio::repository.source() { + local slug=${1} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::repositories "${slug}" "repositories.${slug}.source" '.source' +} + +# ------------------------------------------------------------------------------ +# Returns the URL of a repository. +# +# Arguments: +# $1 Repository slug +# ------------------------------------------------------------------------------ +function bashio::repository.url() { + local slug=${1} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::repositories "${slug}" "repositories.${slug}.url" '.url' +} + +# ------------------------------------------------------------------------------ +# Returns the maintainer of a repository. +# +# Arguments: +# $1 Repository slug +# ------------------------------------------------------------------------------ +function bashio::repository.maintainer() { + local slug=${1} + bashio::log.trace "${FUNCNAME[0]}" "$@" + bashio::repositories "${slug}" "repositories.${slug}.maintainer" '.maintainer' +} diff --git a/lib/secrets.sh b/lib/secrets.sh new file mode 100644 index 0000000..2f44710 --- /dev/null +++ b/lib/secrets.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== + +# ------------------------------------------------------------------------------ +# Gets a secret value by key from secrets.yaml. +# +# Arguments: +# $1 Secret key +# ------------------------------------------------------------------------------ +bashio::secret() { + local key=${1} + local secret + local value + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if ! bashio::fs.directory_exists "$(dirname "${__BASHIO_HA_SECRETS}")"; then + bashio::log.error "This add-on does not support secrets!" + return "${__BASHIO_EXIT_NOK}" + fi + + if ! bashio::fs.file_exists "${__BASHIO_HA_SECRETS}"; then + bashio::log.error \ + "A secret was requested, but could not find a secrets.yaml" + return "${__BASHIO_EXIT_NOK}" + fi + + secret="${key#'!secret '}" + value=$(yq read "${__BASHIO_HA_SECRETS}" "${secret}" ) + + if [[ "${value}" = "null" ]]; then + bashio::log.error "Secret ${secret} not found in secrets.yaml file." + return "${__BASHIO_EXIT_NOK}" + fi + + printf "%s" "${value}" + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Tells whether or not a string might be a secret. +# +# Arguments: +# $1 String to check for a secret +# ------------------------------------------------------------------------------ +bashio::is_secret() { + local string="${1}" + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if [[ "${string}" != '!secret '* ]]; then + return "${__BASHIO_EXIT_NOK}" + fi + return "${__BASHIO_EXIT_OK}" +} diff --git a/lib/string.sh b/lib/string.sh new file mode 100644 index 0000000..bf8b3c0 --- /dev/null +++ b/lib/string.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== + +# ------------------------------------------------------------------------------ +# Converts a string to lower case. +# +# Arguments: +# $1 String to convert +# ------------------------------------------------------------------------------ +function bashio::string.lower() { + local string="${1}" + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + printf "%s" "${string,,}" +} + +# ------------------------------------------------------------------------------ +# Converts a string to upper case. +# +# Arguments: +# $1 String to convert +# ------------------------------------------------------------------------------ +function bashio::string.upper() { + local string="${1}" + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + printf "%s" "${string^^}" +} + +# ------------------------------------------------------------------------------ +# Replaces parts of the string with an other string. +# +# Arguments: +# $1 String to make replacements in +# $2 String part to replace +# $3 String replacement +# ------------------------------------------------------------------------------ +function bashio::string.replace() { + local string="${1}" + local needle="${2}" + local replacement="${3}" + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + printf "%s" "${string//${needle}/${replacement}}" +} + +# ------------------------------------------------------------------------------ +# Returns the length of a string. +# +# Arguments: +# $1 String to determine the length of +# ------------------------------------------------------------------------------ +bashio::string.length() { + local string="${1}" + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + printf "%s" "${#string}" +} + +# ------------------------------------------------------------------------------ +# Returns a substring of a string. +# +# stringZ=abcABC123ABCabc +# hass.string.substring "${stringZ}" 0 # abcABC123ABCabc +# hass.string.substring "${stringZ}" 1 # bcABC123ABCabc +# hass.string.substring "${stringZ}" 7 # 23ABCabc +# hass.string.substring "${stringZ}" 7 3 # 23AB +# +# Arguments: +# $1 String to return a substring off +# $2 Position to start +# $3 Length of the substring (optional) +# ------------------------------------------------------------------------------ +bashio::string.substring() { + local string="${1}" + local position="${2}" + local length="${3:-}" + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if bashio::var.has_value "${length}"; then + printf "%s" "${string:${position}:${length}}" + else + printf "%s" "${string:${position}}" + fi +} diff --git a/lib/supervisor.sh b/lib/supervisor.sh new file mode 100644 index 0000000..88dd12c --- /dev/null +++ b/lib/supervisor.sh @@ -0,0 +1,304 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== + +# ------------------------------------------------------------------------------ +# Check to see if the Supervisor is still alive. +# ------------------------------------------------------------------------------ +function bashio::supervisor.ping() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio GET /supervisor/ping +} + +# ------------------------------------------------------------------------------ +# Updates the Supervisor to the latest version. +# +# Arguments: +# $1 Version to update to (optional) +# ------------------------------------------------------------------------------ +function bashio::supervisor.update() { + local version=${1:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if bashio::var.has_value "${version}"; then + version=$(bashio::var.json version "${version}") + bashio::api.hassio POST /supervisor/update "${version}" + else + bashio::api.hassio POST /supervisor/update + fi + bashio::cache.flush_all +} + +# ------------------------------------------------------------------------------ +# Reloads the Supervisor. +# ------------------------------------------------------------------------------ +function bashio::supervisor.reload() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio POST /supervisor/reload + bashio::cache.flush_all +} + +# ------------------------------------------------------------------------------ +# Returns the logs created by the Supervisor. +# ------------------------------------------------------------------------------ +function bashio::supervisor.logs() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::api.hassio GET /supervisor/logs true +} + +# ------------------------------------------------------------------------------ +# Returns a JSON object with generic version information about the system. +# +# Arguments: +# $1 Cache key to store results in (optional) +# $2 jq Filter to apply on the result (optional) +# ------------------------------------------------------------------------------ +function bashio::supervisor() { + local cache_key=${1:-'supervisor.info'} + local filter=${2:-} + local info + local response + + bashio::log.trace "${FUNCNAME[0]}" "$@" + + if bashio::cache.exists "${cache_key}"; then + bashio::cache.get "${cache_key}" + return "${__BASHIO_EXIT_OK}" + fi + + if bashio::cache.exists 'supervisor.info'; then + info=$(bashio::cache.get 'supervisor.info') + else + info=$(bashio::api.hassio GET /supervisor/info false) + bashio::cache.set 'supervisor.info' "${info}" + fi + + response="${info}" + if bashio::var.has_value "${filter}"; then + response=$(bashio::jq "${info}" "${filter}") + fi + + bashio::cache.set "${cache_key}" "${response}" + printf "%s" "${response}" + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Returns the Hass.io supervisor version used. +# ------------------------------------------------------------------------------ +function bashio::supervisor.version() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::supervisor 'supervisor.info.version' '.version' +} + +# ------------------------------------------------------------------------------ +# Returns the latest version of the Supervisor. +# ------------------------------------------------------------------------------ +function bashio::supervisor.last_version() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::supervisor 'supervisor.info.last_version' '.last_version' +} + +# ------------------------------------------------------------------------------ +# Checks if there is an update available for the Supervisor. +# ------------------------------------------------------------------------------ +function bashio::supervisor.update_available() { + local version + local last_version + + bashio::log.trace "${FUNCNAME[0]}" + + version=$(bashio::supervisor.version) + last_version=$(bashio::supervisor.last_version) + + if [[ "${version}" = "${last_version}" ]]; then + return "${__BASHIO_EXIT_NOK}" + fi + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Returns the architecture of the system. +# ------------------------------------------------------------------------------ +function bashio::supervisor.arch() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::supervisor 'supervisor.info.arch' '.arch' +} + +# ------------------------------------------------------------------------------ +# Returns or sets the stability channel of the setup. +# +# Arguments: +# $1 Stability channel to switch to: stable, beta or dev (optional). +# ------------------------------------------------------------------------------ +function bashio::supervisor.channel() { + local channel=${1:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if bashio::var.has_value "${channel}"; then + channel=$(bashio::var.json channel "${channel}") + bashio::api.hassio POST /supervisor/options "${channel}" + bashio::cache.flush_all + else + bashio::supervisor 'supervisor.info.channel' '.channel // false' + fi +} + +# ------------------------------------------------------------------------------ +# Returns or sets the current timezone of the system. +# +# Arguments: +# $1 Timezone to set (optional). +# ------------------------------------------------------------------------------ +function bashio::supervisor.timezone() { + local timezone=${1:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if bashio::var.has_value "${channel}"; then + channel=$(bashio::var.json timezone "${timezone}") + bashio::api.hassio POST /supervisor/options "${timezone}" + bashio::cache.flush_all + else + bashio::supervisor 'supervisor.info.timezone' '.timezone' + fi +} + +# ------------------------------------------------------------------------------ +# Returns the time to wait after boot in seconds. +# +# Arguments: +# $1 Timezone to set (optional). +# ------------------------------------------------------------------------------ +function bashio::supervisor.wait_boot() { + local wait=${1:-} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if bashio::var.has_value "${wait}"; then + wait=$(bashio::var.json wait_boot "${wait}") + bashio::api.hassio POST /supervisor/options "${wait}" + bashio::cache.flush_all + else + bashio::supervisor 'supervisor.info.wait_boot' '.wait_boot' + fi +} + +# ------------------------------------------------------------------------------ +# Returns a list of add-on slugs of the add-ons installed. +# ------------------------------------------------------------------------------ +function bashio::supervisor.addons() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::supervisor 'supervisor.info.addons' '.addons[].slug' +} + +# ------------------------------------------------------------------------------ +# Returns a list of add-on repositories installed. +# ------------------------------------------------------------------------------ +function bashio::supervisor.addons_repositories() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::supervisor 'supervisor.info.addons_repositories' '.addons_repositories[]' +} + +# ------------------------------------------------------------------------------ +# List all available stats about the Supervisor. +# +# Arguments: +# $1 Cache key to store results in (optional) +# $2 jq Filter to apply on the result (optional) +# ------------------------------------------------------------------------------ +function bashio::supervisor.stats() { + local cache_key=${1:-'supervisor.stats'} + local filter=${2:-} + local info + local response + + bashio::log.trace "${FUNCNAME[0]}" "$@" + + if bashio::cache.exists "${cache_key}"; then + bashio::cache.get "${cache_key}" + return "${__BASHIO_EXIT_OK}" + fi + + if bashio::cache.exists 'supervisor.stats'; then + info=$(bashio::cache.get 'supervisor.stats') + else + info=$(bashio::api.hassio GET /supervisor/stats false) + bashio::cache.set 'supervisor.stats' "${info}" + fi + + response="${info}" + if bashio::var.has_value "${filter}"; then + response=$(bashio::jq "${info}" "${filter}") + fi + + bashio::cache.set "${cache_key}" "${response}" + printf "%s" "${response}" + + return "${__BASHIO_EXIT_OK}" +} + +# ------------------------------------------------------------------------------ +# Returns CPU usage from the Supervisor. +# ------------------------------------------------------------------------------ +function bashio::supervisor.cpu_percent() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::supervisor.stats 'supervisor.stats.cpu_percent' '.cpu_percent' +} + +# ------------------------------------------------------------------------------ +# Returns memory usage from the Supervisor. +# ------------------------------------------------------------------------------ +function bashio::supervisor.memory_usage() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::supervisor.stats 'supervisor.stats.memory_usage' '.memory_usage' +} + +# ------------------------------------------------------------------------------ +# Returns memory limit from the Supervisor. +# ------------------------------------------------------------------------------ +function bashio::supervisor.memory_limit() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::supervisor.stats 'supervisor.stats.memory_limit' '.memory_limit' +} + +# ------------------------------------------------------------------------------ +# Returns outgoing network usage from the Supervisor. +# ------------------------------------------------------------------------------ +function bashio::supervisor.network_tx() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::supervisor.stats 'supervisor.stats.network_tx' '.network_tx' +} + +# ------------------------------------------------------------------------------ +# Returns incoming network usage from the Supervisor. +# ------------------------------------------------------------------------------ +function bashio::supervisor.network_rx() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::supervisor.stats 'supervisor.stats.network_rx' '.network_rx' +} + +# ------------------------------------------------------------------------------ +# Returns disk read usage from the Supervisor. +# ------------------------------------------------------------------------------ +function bashio::supervisor.blk_read() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::supervisor.stats 'supervisor.stats.blk_read' '.blk_read' +} + +# ------------------------------------------------------------------------------ +# Returns disk write usage from the Supervisor. +# ------------------------------------------------------------------------------ +function bashio::supervisor.blk_write() { + bashio::log.trace "${FUNCNAME[0]}" + bashio::supervisor.stats 'supervisor.stats.blk_write' '.blk_write' +} diff --git a/lib/var.sh b/lib/var.sh new file mode 100644 index 0000000..9ce1542 --- /dev/null +++ b/lib/var.sh @@ -0,0 +1,156 @@ +#!/usr/bin/env bash +# ============================================================================== +# Community Hass.io Add-ons: Bashio +# Bashio is an bash function library for use with Hass.io add-ons. +# +# It contains a set of commonly used operations and can be used +# to be included in add-on scripts to reduce code duplication across add-ons. +# ============================================================================== + +# ------------------------------------------------------------------------------ +# Checks if a give value is true. +# +# Arguments: +# $1 value +# ------------------------------------------------------------------------------ +function bashio::var.true() { + local value=${1:-null} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if [[ "${value}" = "true" ]]; then + return "${__BASHIO_EXIT_OK}" + fi + + return "${__BASHIO_EXIT_NOK}" +} + +# ------------------------------------------------------------------------------ +# Checks if a give value is false. +# +# Arguments: +# $1 value +# ------------------------------------------------------------------------------ +function bashio::var.false() { + local value=${1:-null} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if [[ "${value}" = "false" ]]; then + return "${__BASHIO_EXIT_OK}" + fi + + return "${__BASHIO_EXIT_NOK}" +} + +# ------------------------------------------------------------------------------ +# Checks if a global variable is defined. +# +# Arguments: +# $1 Name of the variable +# ------------------------------------------------------------------------------ +bashio::var.defined() { + local variable=${1} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + [[ "${!variable-X}" = "${!variable-Y}" ]] +} + +# ------------------------------------------------------------------------------ +# Checks if a value has actual value. +# +# Arguments: +# $1 Value +# ------------------------------------------------------------------------------ +function bashio::var.has_value() { + local value=${1} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if [[ -n "${value}" ]]; then + return "${__BASHIO_EXIT_OK}" + fi + + return "${__BASHIO_EXIT_NOK}" +} + +# ------------------------------------------------------------------------------ +# Checks if a value is empty. +# +# Arguments: +# $1 Value +# ------------------------------------------------------------------------------ +function bashio::var.is_empty() { + local value=${1} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if [[ -z "${value}" ]]; then + return "${__BASHIO_EXIT_OK}" + fi + + return "${__BASHIO_EXIT_NOK}" +} + +# ------------------------------------------------------------------------------ +# Checks if a value equals. +# +# Arguments: +# $1 Value +# ------------------------------------------------------------------------------ +function bashio::var.is_empty() { + local value=${1} + + bashio::log.trace "${FUNCNAME[0]}:" "$@" + + if [[ -z "${value}" ]]; then + return "${__BASHIO_EXIT_OK}" + fi + + return "${__BASHIO_EXIT_NOK}" +} + +# ------------------------------------------------------------------------------ +# Creates JSON based on function arguments. +# +# Arguments: +# $@ Bash array of key/value pairs, prefix integer or boolean values with ^ +# ------------------------------------------------------------------------------ +function bashio::var.json() { + local data=("$@"); + local number_of_items=${#data[@]} + local json='' + local separator + local counter + local item + + if [[ ${number_of_items} -eq 0 ]]; then + bashio::log.error "Length of input array needs to be at least 2" + return "${__BASHIO_EXIT_NOK}" + fi + + if [[ $((number_of_items%2)) -eq 1 ]]; then + bashio::log.error "Length of input array needs to be even (key/value pairs)" + return "${__BASHIO_EXIT_NOK}" + fi + + counter=0; + for i in "${data[@]}"; do + separator="," + if [ $((++counter%2)) -eq 0 ]; then + separator=":"; + fi + + item="\"$i\"" + if [[ "${i:0:1}" == "^" ]]; then + item="${i:1}" + fi + + json="$json$separator$item"; + done + + echo "{${json:1}}"; + return "${__BASHIO_EXIT_OK}" +} +