From 47d8c506ff4262048365e74e37bcf88db1262640 Mon Sep 17 00:00:00 2001 From: Timmo <28114703+timmo001@users.noreply.github.com> Date: Sat, 18 Aug 2018 14:53:23 +0100 Subject: [PATCH] :sparkles: add initial files --- .editorconfig | 19 + .github/ISSUE_TEMPLATE.md | 20 + .github/PULL_REQUEST_TEMPLATE.md | 9 + .github/autolabeler.yml | 2 + .github/config.yml | 50 ++ .github/invite-contributors.yml | 10 + .github/lock.yml | 20 + .github/move.yml | 20 + .github/no-response.yml | 13 + .github/potential-duplicates.yml | 14 + .github/settings.yml | 150 ++++++ .github/stale.yml | 61 +++ .github/support.yml | 19 + .gitignore | 0 .gitlab-ci.yml | 437 ++++++++++++++++++ .mdlrc | 1 + .yamllint | 64 +++ CODE_OF_CONDUCT.md | 74 +++ CONTRIBUTING.md | 29 ++ LICENSE.md | 21 + README.md | 229 +++++++++ home-panel/.README.j2 | 89 ++++ home-panel/Dockerfile | 66 +++ home-panel/build.json | 10 + home-panel/config.json | 44 ++ home-panel/icon.png | Bin 0 -> 11188 bytes home-panel/logo.png | Bin 0 -> 29594 bytes .../rootfs/etc/cont-init.d/10-config.sh | 19 + home-panel/rootfs/etc/cont-init.d/20-nginx.sh | 38 ++ home-panel/rootfs/etc/cont-init.d/30-api.sh | 18 + .../home-panel/home-panel-config.default.json | 52 +++ home-panel/rootfs/etc/services.d/api/finish | 9 + home-panel/rootfs/etc/services.d/api/run | 14 + .../rootfs/etc/services.d/config/finish | 9 + home-panel/rootfs/etc/services.d/config/run | 16 + home-panel/rootfs/etc/services.d/nginx/finish | 9 + home-panel/rootfs/etc/services.d/nginx/run | 11 + 37 files changed, 1666 insertions(+) create mode 100755 .editorconfig create mode 100755 .github/ISSUE_TEMPLATE.md create mode 100755 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/autolabeler.yml create mode 100644 .github/config.yml create mode 100644 .github/invite-contributors.yml create mode 100644 .github/lock.yml create mode 100644 .github/move.yml create mode 100644 .github/no-response.yml create mode 100644 .github/potential-duplicates.yml create mode 100644 .github/settings.yml create mode 100644 .github/stale.yml create mode 100644 .github/support.yml create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100644 .mdlrc create mode 100644 .yamllint create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 home-panel/.README.j2 create mode 100644 home-panel/Dockerfile create mode 100644 home-panel/build.json create mode 100644 home-panel/config.json create mode 100644 home-panel/icon.png create mode 100644 home-panel/logo.png create mode 100644 home-panel/rootfs/etc/cont-init.d/10-config.sh create mode 100644 home-panel/rootfs/etc/cont-init.d/20-nginx.sh create mode 100644 home-panel/rootfs/etc/cont-init.d/30-api.sh create mode 100644 home-panel/rootfs/etc/home-panel/home-panel-config.default.json create mode 100644 home-panel/rootfs/etc/services.d/api/finish create mode 100644 home-panel/rootfs/etc/services.d/api/run create mode 100644 home-panel/rootfs/etc/services.d/config/finish create mode 100644 home-panel/rootfs/etc/services.d/config/run create mode 100644 home-panel/rootfs/etc/services.d/nginx/finish create mode 100644 home-panel/rootfs/etc/services.d/nginx/run diff --git a/.editorconfig b/.editorconfig new file mode 100755 index 0000000..7a12570 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true +ident_size = 4 + +[*.md] +ident_size = 2 +trim_trailing_whitespace = false + +[*.json] +ident_size = 2 + +[{.gitignore,.gitkeep,.editorconfig}] +ident_size = 2 diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100755 index 0000000..544da8f --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,20 @@ +# Problem/Motivation + +> (Why the issue was filed) + +## Expected behavior + +> (What you expected to happen) + +## Actual behavior + +> (What actually happened) + +## Steps to reproduce + +> (How can someone else make/see it happen) + +## Proposed changes + +> (If you have a proposed change, workaround or fix, +> describe the rationale behind it) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100755 index 0000000..cbd529a --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,9 @@ +# Proposed Changes + +> (Describe the changes and rationale behind them) + +## Related Issues + +> ([Github link][autolink-references] to related issues or pull requests) + +[autolink-references]: https://help.github.com/articles/autolinked-references-and-urls/ \ No newline at end of file diff --git a/.github/autolabeler.yml b/.github/autolabeler.yml new file mode 100644 index 0000000..3ce5703 --- /dev/null +++ b/.github/autolabeler.yml @@ -0,0 +1,2 @@ +--- +"Type: Documentation": ["*.md", "*.j2"] diff --git a/.github/config.yml b/.github/config.yml new file mode 100644 index 0000000..71d2f6d --- /dev/null +++ b/.github/config.yml @@ -0,0 +1,50 @@ +--- +# Configuration for request-info - https://github.com/behaviorbot/request-info + +# *OPTIONAL* Comment to reply with +# Can be either a string : +requestInfoReplyComment: + - "We would appreciate it if you could provide us with more info about this issue/pr!" + - "Hmmm... That issue/PR is kinda low on text. Could you please provide some more content?" + +# *OPTIONAL* default titles to check against for lack of descriptiveness +# MUST BE ALL LOWERCASE +requestInfoDefaultTitles: [] + +# *OPTIONAL* Label to be added to Issues and Pull Requests with insufficient information given +requestInfoLabelToAdd: "Incomplete" + +# *OPTIONAL* Require Pull Requests to contain more information than what is provided in the PR template +# Will fail if the pull request's body is equal to the provided template +checkPullRequestTemplate: true + +# *OPTIONAL* Only warn about insufficient information on these events type +# Keys must be lowercase. Valid values are 'issue' and 'pullRequest' +requestInfoOn: + pullRequest: true + issue: true + +# *OPTIONAL* Add a list of people whose Issues/PRs will not be commented on +# keys must be GitHub usernames +requestInfoUserstoExclude: [] + +# Configuration for new-issue-welcome - https://github.com/behaviorbot/new-issue-welcome + +# Comment to be posted to on first time issues +newIssueWelcomeComment: > + :wave: Thanks for opening your first issue here! + If you're reporting a :bug: bug, please make sure you include steps to reproduce it. + Also, logs, error messages and information about your hardware might be usefull. + +# Configuration for new-pr-welcome - https://github.com/behaviorbot/new-pr-welcome + +# Comment to be posted to on PRs from first time contributors in your repository +newPRWelcomeComment: > + :sparkling_heart: Thanks for opening this pull request! :sparkling_heart: + If your PR gets accepted and merged in, we will invite you to the project :tada: + +# Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge + +# Comment to be posted to on pull requests merged by a first time user +firstPRMergeComment: > + Congrats on merging your first pull request! :tada::tada::tada: diff --git a/.github/invite-contributors.yml b/.github/invite-contributors.yml new file mode 100644 index 0000000..25eb31a --- /dev/null +++ b/.github/invite-contributors.yml @@ -0,0 +1,10 @@ +--- +# If true, this will add new contributors as outside collaborators +# to the repo their PR was merged in. Team name is ignored if this +# flag is set to true. +isOutside: false + +# Specify team name to add new contributors to a specific team +# within your organization. +# Use team name or team-name-slug +team: Contributors diff --git a/.github/lock.yml b/.github/lock.yml new file mode 100644 index 0000000..4b1e816 --- /dev/null +++ b/.github/lock.yml @@ -0,0 +1,20 @@ +--- +# Configuration for lock-threads - https://github.com/dessant/lock-threads +# Number of days of inactivity before a closed issue or pull request is locked +daysUntilLock: 30 + +# Comment to post before locking. Set to `false` to disable +lockComment: > + This thread has been automatically locked because it has not had recent + activity. Please open a new issue for related bugs and link to relevant + comments in this thread. + +# Issues or pull requests with these labels will not be locked +# exemptLabels: +# - no-locking + +# Limit to only `issues` or `pulls` +# only: issues + +# Add a label when locking. Set to `false` to disable +lockLabel: false diff --git a/.github/move.yml b/.github/move.yml new file mode 100644 index 0000000..0c2276a --- /dev/null +++ b/.github/move.yml @@ -0,0 +1,20 @@ +--- +# Delete the command comment when it contains no other content +deleteCommand: true + +# Close the source issue after moving +closeSourceIssue: true + +# Lock the source issue after moving +lockSourceIssue: true + +# Mention issue and comment authors +mentionAuthors: true + +# Preserve mentions in the issue content +keepContentMentions: false + +# Set custom aliases for targets +# aliases: +# r: repo +# or: owner/repo diff --git a/.github/no-response.yml b/.github/no-response.yml new file mode 100644 index 0000000..bb9f0f2 --- /dev/null +++ b/.github/no-response.yml @@ -0,0 +1,13 @@ +--- +# Configuration for probot-no-response - https://github.com/probot/no-response +# Number of days of inactivity before an Issue is closed for lack of response +daysUntilClose: 14 +# Label requiring a response +responseRequiredLabel: "Status: Awaiting response" +# Comment to post when closing an Issue for lack of response. Set to `false` to disable +closeComment: > + This issue has been automatically closed because there has been no response + to our request for more information from the original author. With only the + information that is currently in the issue, we don't have enough information + to take action. Please reach out if you have or find the answers we need so + that we can investigate further. diff --git a/.github/potential-duplicates.yml b/.github/potential-duplicates.yml new file mode 100644 index 0000000..00c7c0f --- /dev/null +++ b/.github/potential-duplicates.yml @@ -0,0 +1,14 @@ +--- +# Label name and color to set, when potential duplicates are detected +issueLabel: "Potential duplicate" +labelColor: e6e6e6 + +# If similarity is higher than this threshold, issue will be marked as duplicate +threshold: 0.70 + +# Comment to post when potential duplicates are detected +referenceComment: > + Potential duplicates found: + {{#issues}} + - [#{{ number }}] {{ title }} ({{ accuracy }}%) + {{/issues}} diff --git a/.github/settings.yml b/.github/settings.yml new file mode 100644 index 0000000..01996ef --- /dev/null +++ b/.github/settings.yml @@ -0,0 +1,150 @@ +--- +repository: + description: "Example - Community Hass.io Add-on for Home Assistant" + homepage: https://addons.community + topics: examples, hassio-addons, hassio, hass, home-assistant, homeassistant, home-automation + private: false + has_issues: true + has_projects: false + has_wiki: false + has_downloads: false + default_branch: master + allow_squash_merge: true + allow_merge_commit: false + allow_rebase_merge: true +labels: + # Priority labels + - name: "Priority: Critical" + color: ee0701 + description: "This should be dealt with ASAP. Not fixing this issue would be a serious error." + - name: "Priority: High" + color: b60205 + description: "After critical issues are fixed, these should be dealt with before any further issues." + - name: "Priority: Medium" + color: 0e8a16 + description: "This issue may be useful, and needs some attention." + - name: "Priority: Low" + color: e4ea8a + description: "Nice addition, maybe... someday..." + + # Type labels + - name: "Type: Bug" + color: ee0701 + description: "Inconsistencies or issues which will cause a problem for users or implementors." + - name: "Type: Documentation" + color: 0052cc + description: "Solely about the documentation of the project." + - name: "Type: Enhancement" + color: 1d76db + description: "Enhancement of the code, not introducing new features." + - name: "Type: Feature" + color: 0e8a16 + description: "New features or options." + - name: "Type: Support" + color: 5319e7 + description: "Marks an issue as an support ticket." + - name: "Type: Discussion" + color: d4c5f9 + description: "Marks an issue as an generic discussion ticket." + - name: "Type: Maintaince" + color: 2af79e + description: "Generic maintaince tasks, e.g., package updates." + + # Additional markers + - name: "Security" + color: ee0701 + description: "Marks an security issues that needs to be resolved asap." + - name: "Idea" + color: fef2c0 + description: "Marks an idea, which might be excepted and implemented." + - name: "Incomplete" + color: fef2c0 + description: "Marks an PR or issue that is missing information." + - name: "Pull request" + color: fbca04 + description: "There is an PR opened for this issue." + - name: "Accepted" + color: c2e0c6 + description: "This issue or PR has been accepted." + - name: "Declined" + color: f9d0c4 + description: "This issue or PR has been declined." + - name: "Potential duplicate" + color: e6e6e6 + description: "This issue has been automatically marked as a potential duplicate." + + # Ongoing Status labels + - name: "Status: Triage" + color: fbca04 + description: "This issue needs to be triaged." + - name: "Status: On hold" + color: cccccc + description: "Issue or PR that has been placed on hold for now." + - name: "Status: In progress" + color: fbca04 + description: "Issue is currently being resolved by a developer." + - name: "Status: Stale" + color: fef2c0 + description: "There has not been activity on this issue or PR for quite some time." + - name: "Status: Awaiting response" + color: fef2c0 + description: "Issue or PR awaits response from the creator." + - name: "Status: Blocked" + color: fef2c0 + description: "Progress on this issue is currently not possible." + + # Closing status labels + - name: "Closed: Known limitation" + color: e6e6e6 + description: "Issue is closed, it is a known limitation." + - name: "Closed: Expected behavior" + color: e6e6e6 + description: "Issues is closed, it is expected behavior." + - name: "Closed: Duplicate" + color: e6e6e6 + description: "Issue is closed, duplicate of an existing issue." + - name: "Closed: Invalid" + color: e6e6e6 + description: "Issue is closed, marked as not a valid issue (e.g., an user error)." + - name: "Closed: Wrong repository" + color: e6e6e6 + description: "Issue is closed, was created in the wrong repository." + - name: "Closed: Won't Fix" + color: e6e6e6 + description: "Issue is closed, it won't be fixed." + - name: "Closed: Done" + color: c2e0c6 + description: "Issue closed, work on this issue has been marked complete." + + # Others + - name: "Beginner Friendly" + color: 0e8a16 + description: "Good first issue for people wanting to contribute to the project." + - name: "Help wanted" + color: 0e8a16 + description: "We need some extra helping hands or expertise in order to resolve this." + - name: "Hacktoberfest" + description: "Issues/PRs are participating in the Hacktoberfest" + color: fbca04 + +branches: + - name: master + protection: + required_pull_request_reviews: + # required_approving_review_count: 1 + dismiss_stale_reviews: true + require_code_owner_reviews: true + dismissal_restrictions: + users: [] + teams: + - Admins + - Masters + required_status_checks: + strict: false + contexts: [] + enforce_admins: false + restrictions: + users: [] + teams: + - Admins + - Masters diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000..36938bb --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,61 @@ +--- +# Configuration for probot-stale - https://github.com/probot/stale + +# Number of days of inactivity before an Issue or Pull Request becomes stale +daysUntilStale: 60 + +# Number of days of inactivity before a stale Issue or Pull Request is closed. +# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. +daysUntilClose: 7 + +# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable +exemptLabels: + - "Status: On hold" + - "Status: In progress" + - "Status: Awaiting response" + - "Status: Blocked" + - "Idea" + - "Security" + +# Set to true to ignore issues in a project (defaults to false) +exemptProjects: false + +# Set to true to ignore issues in a milestone (defaults to false) +exemptMilestones: false + +# Label to use when marking as stale +staleLabel: "Status: Stale" + +# Comment to post when marking as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. + +# Comment to post when removing the stale label. +# unmarkComment: > +# Your comment here. +unmarkComment: false + +# Comment to post when closing a stale Issue or Pull Request. +# closeComment: > +# Your comment here. +closeComment: false + +# Limit the number of actions per hour, from 1-30. Default is 30 +limitPerRun: 30 + +# Limit to only `issues` or `pulls` +only: issues + +# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': +# pulls: +# daysUntilStale: 30 +# markComment: > +# This pull request has been automatically marked as stale because it has not had +# recent activity. It will be closed if no further activity occurs. Thank you +# for your contributions. + +# issues: +# exemptLabels: +# - confirmed diff --git a/.github/support.yml b/.github/support.yml new file mode 100644 index 0000000..4ad863a --- /dev/null +++ b/.github/support.yml @@ -0,0 +1,19 @@ +--- +--- +# Configuration for support-requests - https://github.com/dessant/support-requests + +# Label used to mark issues as support requests +supportLabel: "Type: Support" + +# Comment to post on issues marked as support requests. Add a link +# to a support page, or set to `false` to disable +supportComment: > + :wave: We use the issue tracker exclusively for bug reports and feature requests. + However, this issue appears to be a support request. Please use our + support channels to get help with the project. + +# Close issues marked as support requests +close: true + +# Lock issues marked as support requests +lock: false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..e44a435 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,437 @@ +--- +image: docker:latest + +variables: + ADDON_GITHUB_REPO: timmo001/addon-home-panel + ADDON_SLUG: home-panel + ADDON_TARGET: home-panel + DOCKER_DRIVER: overlay2 + DOCKER_HUB_ORG: hassioaddons + +stages: + - preflight + - build + - scan + - deploy + - manifest + - publish + +# Generic DIND template +.dind: &dind + before_script: + - docker info + services: + - name: docker:dind + command: ["--experimental"] + +# Generic preflight template +.preflight: &preflight + stage: preflight + tags: + - preflight + +# Generic build template +.build: &build + <<: *dind + stage: build + before_script: + - docker info + - | + if [ "$(apk --print-arch)" = "amd64" ]; then + docker run --rm --privileged hassioaddons/qemu-user-static:latest + fi + - | + echo "${CI_JOB_TOKEN}" | docker login \ + --username gitlab-ci-token \ + --password-stdin \ + registry.gitlab.com + - docker pull "registry.gitlab.com/${CI_PROJECT_PATH}/${ADDON_ARCH}:cache" || true + script: + - | + docker build \ + --build-arg "BUILD_FROM=${FROM}" \ + --build-arg "BUILD_DATE=$(date +"%Y-%m-%dT%H:%M:%SZ")" \ + --build-arg "BUILD_ARCH=${ADDON_ARCH}" \ + --build-arg "BUILD_REF=${CI_COMMIT_SHA}" \ + --build-arg "BUILD_VERSION=${CI_COMMIT_TAG:-${CI_COMMIT_SHA:0:7}}" \ + --cache-from "registry.gitlab.com/${CI_PROJECT_PATH}/${ADDON_ARCH}:cache" \ + --tag \ + "registry.gitlab.com/${CI_PROJECT_PATH}/${ADDON_ARCH}:${CI_COMMIT_SHA}" \ + "${ADDON_TARGET}" + - | + docker push \ + "registry.gitlab.com/${CI_PROJECT_PATH}/${ADDON_ARCH}:${CI_COMMIT_SHA}" + +# Generic scan template +.scan: &scan + <<: *dind + stage: scan + allow_failure: true + before_script: + - docker info + - docker run -d --name db arminc/clair-db:latest + - docker run -p 6060:6060 --link db:postgres -d --name clair arminc/clair-local-scan:v2.0.1 + - apk add -U curl ca-certificates + - | + curl \ + --silent \ + --show-error \ + --location \ + --fail \ + --retry 3 \ + --output /usr/bin/clair-scanner \ + https://github.com/arminc/clair-scanner/releases/download/v8/clair-scanner_linux_amd64 + - chmod +x /usr/bin/clair-scanner + - touch clair-whitelist.yml + - echo "Waiting for Clair to start" + - | + while ! nc -z docker 6060; do + sleep 1 + WAIT=$((${WAIT} + 1)) + if [ "${WAIT}" -gt 30 ]; then + echo "Error > Timeout waiting for Clair to start" + exit 1 + fi + done + - docker pull "registry.gitlab.com/${CI_PROJECT_PATH}/${ADDON_ARCH}:${CI_COMMIT_SHA}" + script: + - | + clair-scanner \ + -c http://docker:6060 \ + --ip $(hostname -i) \ + -w clair-whitelist.yml \ + "registry.gitlab.com/${CI_PROJECT_PATH}/${ADDON_ARCH}:${CI_COMMIT_SHA}" + tags: + - scan + +# Generic deploy template +.deploy: &deploy + <<: *dind + stage: deploy + before_script: + - docker info + - docker pull "registry.gitlab.com/${CI_PROJECT_PATH}/${ADDON_ARCH}:${CI_COMMIT_SHA}" + - | + echo "${CI_JOB_TOKEN}" | docker login \ + --username gitlab-ci-token \ + --password-stdin \ + registry.gitlab.com + - | + echo "${DOCKER_PASSWORD}" | docker login \ + --username "${DOCKER_LOGIN}" \ + --password-stdin + script: + - | + docker tag \ + "registry.gitlab.com/${CI_PROJECT_PATH}/${ADDON_ARCH}:${CI_COMMIT_SHA}" \ + "registry.gitlab.com/${CI_PROJECT_PATH}/${ADDON_ARCH}:cache" + - docker push "registry.gitlab.com/${CI_PROJECT_PATH}/${ADDON_ARCH}:cache" + - TAG="${CI_COMMIT_TAG#v}" + - TAG="${TAG:-${CI_COMMIT_SHA:0:7}}" + - | + docker tag \ + "registry.gitlab.com/${CI_PROJECT_PATH}/${ADDON_ARCH}:${CI_COMMIT_SHA}" \ + "${DOCKER_HUB_ORG}/${ADDON_SLUG}:${ADDON_ARCH}-${TAG}" + - | + docker push \ + "${DOCKER_HUB_ORG}/${ADDON_SLUG}:${ADDON_ARCH}-${TAG}" + - | + docker tag \ + "registry.gitlab.com/${CI_PROJECT_PATH}/${ADDON_ARCH}:${CI_COMMIT_SHA}" \ + "${DOCKER_HUB_ORG}/${ADDON_SLUG}-${ADDON_ARCH}:${TAG}" + - | + docker push \ + "${DOCKER_HUB_ORG}/${ADDON_SLUG}-${ADDON_ARCH}:${TAG}" + tags: + - deploy + only: + - master + - /^v\d+\.\d+\.\d+(?:-(?:beta|rc)(?:(?:(?:\+|\.)?[a-zA-Z0-9]+)*)?)?$/ + except: + - /^(?!master).+@/ + +# Generic manifest template +.manifest: &manifest + <<: *dind + stage: manifest + before_script: + - mkdir -p ~/.docker + - echo '{"experimental":"enabled"}' > ~/.docker/config.json + - docker info + - | + echo "${DOCKER_PASSWORD}" | docker login \ + --username "${DOCKER_LOGIN}" \ + --password-stdin + script: + - TAG="${TAG#v}" + - TAG="${TAG:-${CI_COMMIT_SHA:0:7}}" + - REF="${CI_COMMIT_TAG#v}" + - REF="${REF:-${CI_COMMIT_SHA:0:7}}" + - | + docker manifest create \ + "${DOCKER_HUB_ORG}/${ADDON_SLUG}:${TAG}" \ + # "${DOCKER_HUB_ORG}/${ADDON_SLUG}:aarch64-${REF}" \ + "${DOCKER_HUB_ORG}/${ADDON_SLUG}:amd64-${REF}" \ + "${DOCKER_HUB_ORG}/${ADDON_SLUG}:armhf-${REF}" \ + # "${DOCKER_HUB_ORG}/${ADDON_SLUG}:i386-${REF}" + # - | + # docker manifest annotate \ + # "${DOCKER_HUB_ORG}/${ADDON_SLUG}:${TAG}" \ + # "${DOCKER_HUB_ORG}/${ADDON_SLUG}:aarch64-${REF}" \ + # --os=linux \ + # --arch=arm64 \ + # --variant=v8 + - | + docker manifest annotate \ + "${DOCKER_HUB_ORG}/${ADDON_SLUG}:${TAG}" \ + "${DOCKER_HUB_ORG}/${ADDON_SLUG}:amd64-${REF}" \ + --os=linux \ + --arch=amd64 + - | + docker manifest annotate \ + "${DOCKER_HUB_ORG}/${ADDON_SLUG}:${TAG}" \ + "${DOCKER_HUB_ORG}/${ADDON_SLUG}:armhf-${REF}" \ + --os=linux \ + --arch=arm \ + --variant=v6 + # - | + # docker manifest annotate \ + # "${DOCKER_HUB_ORG}/${ADDON_SLUG}:${TAG}" \ + # "${DOCKER_HUB_ORG}/${ADDON_SLUG}:i386-${REF}" \ + # --os=linux \ + # --arch=386 + - | + docker manifest push \ + "${DOCKER_HUB_ORG}/${ADDON_SLUG}:${TAG}" + tags: + - manifest + except: + - /^(?!master).+@/ + +# Generic publish template +.publish: &publish + stage: publish + image: + name: hassioaddons/repository-updater:latest + entrypoint: [""] + script: + - | + repository-updater \ + --token "${GITHUB_TOKEN}" \ + --repository "${REPOSITORY}" \ + --addon "${ADDON_GITHUB_REPO}" + tags: + - publish + except: + - /^(?!master).+@/ + +# Preflight jobs +hadolint: + <<: *preflight + image: hadolint/hadolint:latest-debian + before_script: + - hadolint --version + script: + - hadolint "${ADDON_TARGET}/Dockerfile" + +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 . + +# Build Jobs +build:armhf: + <<: *build + variables: + ADDON_ARCH: armhf + FROM: hassioaddons/base-armhf:2.0.0 + tags: + - build + - armhf + +# build:aarch64: +# <<: *build +# variables: +# ADDON_ARCH: aarch64 +# FROM: hassioaddons/base-aarch64:2.0.0 +# tags: +# - build +# - aarch64 + +# build:i386: +# <<: *build +# variables: +# ADDON_ARCH: i386 +# FROM: hassioaddons/base-i386:2.0.0 +# tags: +# - build +# - i386 + +build:amd64: + <<: *build + variables: + ADDON_ARCH: amd64 + FROM: hassioaddons/base-amd64:2.0.0 + tags: + - build + - amd64 + +# Scan jobs +clair:armhf: + <<: *scan + variables: + ADDON_ARCH: armhf + +# clair:aarch64: +# <<: *scan +# variables: +# ADDON_ARCH: aarch64 + +# clair:i386: +# <<: *scan +# variables: +# ADDON_ARCH: i386 + +clair:amd64: + <<: *scan + variables: + ADDON_ARCH: amd64 + +# Deploy jobs +deploy:armhf: + <<: *deploy + variables: + ADDON_ARCH: armhf + +# deploy:aarch64: +# <<: *deploy +# variables: +# ADDON_ARCH: aarch64 + +# deploy:i386: +# <<: *deploy +# variables: +# ADDON_ARCH: i386 + +deploy:amd64: + <<: *deploy + variables: + ADDON_ARCH: amd64 + +# Manifest jobs +manifest:sha: + <<: *manifest + only: + - master + +manifest:version: + <<: *manifest + variables: + TAG: "${CI_COMMIT_TAG}" + only: + - /^v\d+\.\d+\.\d+(?:-(?:beta|rc)(?:(?:(?:\+|\.)?[a-zA-Z0-9]+)*)?)?$/ + +manifest:stable: + <<: *manifest + variables: + TAG: latest + only: + - /^v\d+\.\d+\.\d+(?:(?:(?:\+|\.)?[a-zA-Z0-9]+)*)?$/ + +manifest:beta: + <<: *manifest + variables: + TAG: beta + only: + - /^v\d+\.\d+\.\d+(?:-(?:beta|rc)(?:(?:(?:\+|\.)?[a-zA-Z0-9]+)*)?)?$/ + +manifest:edge: + <<: *manifest + variables: + TAG: edge + only: + - master + +# Publish jobs +publish:stable: + <<: *publish + variables: + REPOSITORY: timmo001/repository + only: + - /^v\d+\.\d+\.\d+(?:(?:(?:\+|\.)?[a-zA-Z0-9]+)*)?$/ + environment: + name: stable + +publish:beta: + <<: *publish + variables: + REPOSITORY: timmo001/repository-beta + only: + - /^v\d+\.\d+\.\d+(?:-(?:beta|rc)(?:(?:(?:\+|\.)?[a-zA-Z0-9]+)*)?)?$/ + environment: + name: beta + +publish:edge: + <<: *publish + variables: + REPOSITORY: timmo001/repository-edge + only: + - master + environment: + name: edge diff --git a/.mdlrc b/.mdlrc new file mode 100644 index 0000000..2b0128d --- /dev/null +++ b/.mdlrc @@ -0,0 +1 @@ +rules "~MD024" \ No newline at end of file diff --git a/.yamllint b/.yamllint new file mode 100644 index 0000000..0a2a889 --- /dev/null +++ b/.yamllint @@ -0,0 +1,64 @@ +--- +rules: + braces: + level: error + min-spaces-inside: 0 + max-spaces-inside: 1 + min-spaces-inside-empty: -1 + max-spaces-inside-empty: -1 + brackets: + level: error + min-spaces-inside: 0 + max-spaces-inside: 0 + min-spaces-inside-empty: -1 + max-spaces-inside-empty: -1 + colons: + level: error + max-spaces-before: 0 + max-spaces-after: 1 + commas: + level: error + max-spaces-before: 0 + min-spaces-after: 1 + max-spaces-after: 1 + comments: + level: error + require-starting-space: true + min-spaces-from-content: 2 + comments-indentation: + level: error + document-end: + level: error + present: false + document-start: + level: error + present: true + empty-lines: + level: error + max: 1 + max-start: 0 + max-end: 1 + hyphens: + level: error + max-spaces-after: 1 + indentation: + level: error + spaces: 2 + indent-sequences: true + check-multi-line-strings: false + key-duplicates: + level: error + line-length: + level: warning + max: 120 + allow-non-breakable-words: true + allow-non-breakable-inline-mappings: true + new-line-at-end-of-file: + level: error + new-lines: + level: error + type: unix + trailing-spaces: + level: error + truthy: + level: error diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..2919457 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Code of conduct + +## Our pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our standards + +Examples of behavior that contributes to creating a positive environment +include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention + or advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or + electronic address, without explicit permission +- Other conduct which could reasonably be considered inappropriate + in a professional setting + +## Our responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project lead. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project lead is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..8170fb3 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,29 @@ +# Contributing + +When contributing to this repository, please first discuss the change you wish +to make via issue, email, or any other method with the owners of this repository +before making a change. + +Please note we have a code of conduct, please follow it in all your interactions +with the project. + +## Issues and feature requests + +You've found a bug in the source code, a mistake in the documentation or maybe +you'd like a new feature? You can help us by submitting an issue to our +[GitHub Repository][github]. Before you create an issue, make sure you search +the archive, maybe your question was already answered. + +Even better: You could submit a pull request with a fix / new feature! + +## Pull request process + +1. Search our repository for open or closed [pull requests][prs] that relates + to your submission. You don't want to duplicate effort. + +1. You may merge the pull request in once you have the sign-off of two other + developers, or if you do not have permission to do that, you may request + the second reviewer to merge it for you. + +[github]: https://github.com/timmo001/addon-home-panel/issues +[prs]: https://github.com/timmo001/addon-home-panel/pulls diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..f3cbe37 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) Timmo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..272cdf7 --- /dev/null +++ b/README.md @@ -0,0 +1,229 @@ +# Timmo Hass.io Add-ons: Home Panel + +[![GitHub Release][releases-shield]][releases] +![Project Stage][project-stage-shield] +[![License][license-shield]](LICENSE.md) + +[![GitLab CI][gitlabci-shield]][gitlabci] +![Project Maintenance][maintenance-shield] +[![GitHub Activity][commits-shield]][commits] + +[![Bountysource][bountysource-shield]][bountysource] + +[Home Panel][home-panel] add-on + +## About + +A touch-compatible web-app for controlling the home. Integrates with + [Home Assistant][hass] as an alternative / additional frontend. + +## Features + +- Card based user interface with support for [HASS][hass] entities, links and + cameras. +- Supports and can be used as alternate / additional frontend for + [Home Assistant][hass] +- Supports MJPEG and related image-based camera/image feeds + (can also be used as a photo frame) +- Light control with brightness, temperature, color, effects etc. support +- Supports Radio playback from TuneIn API +- Add weather and weather icons using Home Assistant's + [Dark Sky](https://www.home-assistant.io/components/weather.darksky/) + component +- Made for touch screens with a sideways scrolling Material + Design interface. (Compatible with desktops as well) + +## Screenshots + +![Light Theme Screenshot][light-theme] +![More Info Light Screenshot][more-info-light] + +![Dark Theme Screenshot][dark-theme] +![More Info Dark Screenshot][more-info-dark] + +![Radio Screenshot][radio] + +## Installation + +The installation of this add-on is pretty straightforward and not different in +comparison to installing any other Hass.io add-on. + +1. [Add our Hass.io add-ons repository][repository] to your Hass.io instance. +1. Install the "Home Panel" add-on +1. Configure the "Home Panel" add-on (See below) +1. Start the "Home Panel" add-on +1. Check the logs of the "Home Panel" add-on to see it in action. + +**NOTE**: Do not add this repository to Hass.io, please use: +`https://github.com/timmo001/repository`. + +## Docker status + +![Supports armhf Architecture][armhf-shield] +![Supports aarch64 Architecture][aarch64-shield] +![Supports amd64 Architecture][amd64-shield] +![Supports i386 Architecture][i386-shield] + +[![Docker Version][version-shield]][microbadger] +[![Docker Layers][layers-shield]][microbadger] +[![Docker Pulls][pulls-shield]][dockerhub] + +## Configuration + +**Note**: _Remember to restart the add-on when the configuration is changed._ + +Example add-on configuration: + +```json +{ + "log_level": "info", + "ssl": true, + "certfile": "fullchain.pem", + "keyfile": "privkey.pem", + "config_file": "home-panel-config.json" +} +``` + +### Option: `log_level` + +The `log_level` option controls the level of log output by the addon and can +be changed to be more or less verbose, which might be useful when you are +dealing with an unknown issue. Possible values are: + +- `trace`: Show every detail, like all called internal functions. +- `debug`: Shows detailed debug information. +- `info`: Normal (usually) interesting events. +- `warning`: Exceptional occurrences that are not errors. +- `error`: Runtime errors that do not require immediate action. +- `fatal`: Something went terribly wrong. Add-on becomes unusable. + +Please note that each level automatically includes log messages from a +more severe level, e.g., `debug` also shows `info` messages. By default, +the `log_level` is set to `info`, which is the recommended setting unless +you are troubleshooting. + +### Option: `ssl` + +Enables/Disables SSL (HTTPS) on the IDE. Set it `true` to enable it, +`false` otherwise. + +### Option: `certfile` + +The certificate file to use for SSL. + +**Note**: _The file MUST be stored in `/ssl/`, which is default for Hass.io_ + +### Option: `keyfile` + +The private key file to use for SSL. + +**Note**: _The file MUST be stored in `/ssl/`, which is default for Hass.io_ + +### Option: `config_file` + +The location of your config.json in /config. + +## Changelog & Releases + +This repository keeps a change log using [GitHub's releases][releases] +functionality. The format of the log is based on +[Keep a Changelog][keepchangelog]. + +Releases are based on [Semantic Versioning][semver], and use the format +of ``MAJOR.MINOR.PATCH``. In a nutshell, the version will be incremented +based on the following: + +- ``MAJOR``: Incompatible or major changes. +- ``MINOR``: Backwards-compatible new features and enhancements. +- ``PATCH``: Backwards-compatible bugfixes and package updates. + +## Support + +You can [open an issue here][issue] on GitHub. + +## Contributing + +This is an active open-source project. We are always open to people who want to +use the code or contribute to it. + +We have set up a separate document containing our +[contribution guidelines](CONTRIBUTING.md). + +Thank you for being involved! :heart_eyes: + +## Authors & contributors + +The original setup of this repository is by [Timmo][Timmo]. + +For a full list of all authors and contributors, +check [the contributor's page][contributors]. + +## We have got some Hass.io add-ons for you + +Want some more functionality to your Hass.io Home Assistant instance? + +We have created multiple add-ons for Hass.io. For a full list, check out +our [GitHub Repository][repository]. + +## License + +MIT License + +Copyright (c) Timmo + +Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + 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. + +[aarch64-shield]: https://img.shields.io/badge/aarch64-yes-green.svg +[amd64-shield]: https://img.shields.io/badge/amd64-yes-green.svg +[anchore-shield]: https://anchore.io/service/badges/image/8f74a497abc908834244d697a67675ecd13080199270598283c8e0cea1b1723e +[armhf-shield]: https://img.shields.io/badge/armhf-yes-green.svg +[bountysource-shield]: https://img.shields.io/bountysource/team/timmo001/activity.svg +[bountysource]: https://www.bountysource.com/teams/timmo001/issues +[commits-shield]: https://img.shields.io/github/commit-activity/y/timmo001/addon-home-panel.svg +[commits]: https://github.com/timmo001/addon-home-panel/commits/master +[contributors]: https://github.com/timmo001/addon-home-panel/graphs/contributors +[dockerhub]: https://hub.docker.com/r/hassioaddons/home-panel +[forum-shield]: https://img.shields.io/badge/community-forum-brightgreen.svg +[timmo]: https://github.com/timmo001 +[gitlabci-shield]: https://gitlab.com/timmo001/addon-home-panel/badges/master/pipeline.svg +[gitlabci]: https://gitlab.com/timmo001/addon-home-panel/pipelines +[i386-shield]: https://img.shields.io/badge/i386-yes-green.svg +[issue]: https://github.com/timmo001/addon-home-panel/issues +[keepchangelog]: http://keepachangelog.com/en/1.0.0/ +[layers-shield]: https://images.microbadger.com/badges/image/hassioaddons/home-panel.svg +[license-shield]: https://img.shields.io/github/license/timmo001/addon-home-panel.svg +[maintenance-shield]: https://img.shields.io/maintenance/yes/2018.svg +[microbadger]: https://microbadger.com/images/hassioaddons/home-panel +[project-stage-shield]: https://img.shields.io/badge/project%20stage-production%20ready-brightgreen.svg +[pulls-shield]: https://img.shields.io/docker/pulls/hassioaddons/home-panel.svg +[reddit]: https://reddit.com/r/homeassistant +[releases-shield]: https://img.shields.io/github/release/timmo001/addon-home-panel.svg +[releases]: https://github.com/timmo001/addon-home-panel/releases +[repository]: https://github.com/timmo001/repository +[semver]: http://semver.org/spec/v2.0.0.html +[version-shield]: https://images.microbadger.com/badges/version/hassioaddons/home-panel.svg +[home-panel]: https://github.com/timmo001/home-panel +[light-theme]: https://raw.githubusercontent.com/timmo001/home-panel/master/docs/resources/light-theme.png +[dark-theme]: https://raw.githubusercontent.com/timmo001/home-panel/master/docs/resources/dark-theme.png +[more-info-light]: https://raw.githubusercontent.com/timmo001/home-panel/master/docs/resources/more-info-light.png +[more-info-dark]: https://raw.githubusercontent.com/timmo001/home-panel/master/docs/resources/more-info-dark.png +[radio]: https://raw.githubusercontent.com/timmo001/home-panel/master/docs/resources/radio.png +[hass]: https://www.home-assistant.io/ +[docs]: https://git.timmo.xyz/home-panel/ +[config]: https://git.timmo.xyz/home-panel/configuration/ diff --git a/home-panel/.README.j2 b/home-panel/.README.j2 new file mode 100644 index 0000000..dbcef36 --- /dev/null +++ b/home-panel/.README.j2 @@ -0,0 +1,89 @@ +# Timmo Hass.io Add-ons: Home Panel + +[![Release][release-shield]][release] ![Project Stage][project-stage-shield] ![Project Maintenance][maintenance-shield] + +[Home Panel][home-panel] add-on + +## About + +A touch-compatible web-app for controlling the home. Integrates with + [Home Assistant][hass] as an alternative / additional frontend. + +### Features + +- Card based user interface with support for [HASS][hass] entities, links and + cameras. +- Supports and can be used as alternate / additional frontend for + [Home Assistant][hass] +- Supports MJPEG and related image-based camera/image feeds + (can also be used as a photo frame) +- Light control with brightness, temperature, color, effects etc. support +- Supports Radio playback from TuneIn API +- Add weather and weather icons using Home Assistant's + [Dark Sky](https://www.home-assistant.io/components/weather.darksky/) + component +- Made for touch screens with a sideways scrolling Material + Design interface. (Compatible with desktops as well) + +### Screenshots + +![Light Theme Screenshot][light-theme] +![More Info Light Screenshot][more-info-light] + +![Dark Theme Screenshot][dark-theme] +![More Info Dark Screenshot][more-info-dark] + +![Radio Screenshot][radio] + +[Click here for the full documentation][docs] + +{% if channel == "edge" %} +## WARNING! THIS IS AN EDGE VERSION! + +This Hass.io Add-ons repository contains edge builds of add-ons. Edge builds +add-ons are based upon the latest development version. + +- They may not work at all. +- They might stop working at any time. +- They could have a negative impact on your system. + +This repository was created for: + +- Anybody willing to test. +- Anybody interested in trying out upcoming add-ons or add-on features. +- Developers. + +If you are more interested in stable releases of our add-ons: + + + +{% endif %} +{% if channel == "beta" %} +## WARNING! THIS IS A BETA VERSION! + +This Hass.io Add-ons repository contains beta releases of add-ons. + +- They might stop working at any time. +- They could have a negative impact on your system. + +This repository was created for: + +- Anybody willing to test. +- Anybody interested in trying out upcoming add-ons or add-on features. + +If you are more interested in stable releases of our add-ons: + + + +{% endif %} +[project-stage-shield]: https://img.shields.io/badge/project%20stage-production%20ready-brightgreen.svg +[maintenance-shield]: https://img.shields.io/maintenance/yes/2018.svg +[release-shield]: https://img.shields.io/badge/version-{{ version }}-blue.svg +[release]: {{ repo }}/tree/{{ version }} +[docs]: {{ repo }}/blob/{{ version }}/README.md +[buymeacoffee-shield]: https://www.buymeacoffee.com/assets/img/guidelines/download-assets-sm-2.svg +[light-theme]: https://raw.githubusercontent.com/timmo001/home-panel/master/docs/resources/light-theme.png +[dark-theme]: https://raw.githubusercontent.com/timmo001/home-panel/master/docs/resources/dark-theme.png +[more-info-light]: https://raw.githubusercontent.com/timmo001/home-panel/master/docs/resources/more-info-light.png +[more-info-dark]: https://raw.githubusercontent.com/timmo001/home-panel/master/docs/resources/more-info-dark.png +[radio]: https://raw.githubusercontent.com/timmo001/home-panel/master/docs/resources/radio.png diff --git a/home-panel/Dockerfile b/home-panel/Dockerfile new file mode 100644 index 0000000..c13dff9 --- /dev/null +++ b/home-panel/Dockerfile @@ -0,0 +1,66 @@ +ARG BUILD_FROM=hassioaddons/base:2.0.0 +# hadolint ignore=DL3006 +FROM ${BUILD_FROM} + +# Copy root filesystem +COPY rootfs / + +# Install packages +RUN \ + apk add --no-cache \ + nodejs-current=9.11.1-r2 \ + yarn=1.7.0-r0 \ + nginx=1.14.0-r0 \ + git=2.18.0-r0 \ + wget=1.19.5-r0 \ + zip=3.0-r6 \ + inotify-tools=3.20.1-r1 + +# Create nginx directories +RUN mkdir -p /run/nginx && mkdir -p /usr/share/nginx/html + +# App +WORKDIR /usr/src/app + +# Download and unzip into nginx html directory +RUN \ + wget https://github.com/timmo001/home-panel/releases/download/v0.5.2/home-panel-built.zip \ + && unzip home-panel-built.zip \ + && rm -Rf /usr/share/nginx/html/* \ + && mv build/* /usr/share/nginx/html \ + && rm -Rf ./* + +# API +WORKDIR /usr/src/api + +# Clone and checkout API release +RUN \ + git clone https://github.com/timmo001/home-panel-api.git ./ \ + && git checkout v0.2.2 + +# Install dependencies +RUN yarn install && yarn cache clean + +# Build arugments +ARG BUILD_ARCH +ARG BUILD_DATE +ARG BUILD_REF +ARG BUILD_VERSION + +# Labels +LABEL \ + io.hass.name="Home Panel" \ + io.hass.description="A touch-compatible web-app for controlling the home" \ + io.hass.arch="${BUILD_ARCH}" \ + io.hass.type="addon" \ + io.hass.version=${BUILD_VERSION} \ + maintainer="Timmo" \ + org.label-schema.description="A touch-compatible web-app for controlling the home" \ + org.label-schema.build-date=${BUILD_DATE} \ + org.label-schema.name="Home Panel" \ + org.label-schema.schema-version="1.0" \ + org.label-schema.url="https://git.timmo.xyz/home-panel" \ + org.label-schema.usage="https://github.com/timmo001/addon-home-panel/tree/master/README.md" \ + org.label-schema.vcs-ref=${BUILD_REF} \ + org.label-schema.vcs-url="https://github.com/timmo001/addon-home-panel" \ + org.label-schema.vendor="Timmo Hass.io Addons" diff --git a/home-panel/build.json b/home-panel/build.json new file mode 100644 index 0000000..47efe3f --- /dev/null +++ b/home-panel/build.json @@ -0,0 +1,10 @@ +{ + "squash": false, + "build_from": { + "aarch64": "hassioaddons/base-aarch64:2.1.1", + "amd64": "hassioaddons/base-amd64:2.1.1", + "armhf": "hassioaddons/base-armhf:2.1.1", + "i386": "hassioaddons/base-i386:2.1.1" + }, + "args": {} +} diff --git a/home-panel/config.json b/home-panel/config.json new file mode 100644 index 0000000..fbe5432 --- /dev/null +++ b/home-panel/config.json @@ -0,0 +1,44 @@ +{ + "name": "Home Panel", + "version": "dev", + "slug": "home-panel", + "description": "A touch-compatible web-app for controlling the home", + "url": "https://github.com/timmo001/addon-home-panel", + "webui": "[PROTO:ssl]://[HOST]:[PORT:8234]", + "startup": "application", + "arch": [ + "aarch64", + "amd64", + "armhf", + "i386" + ], + "boot": "auto", + "hassio_api": true, + "homeassistant_api": true, + "host_network": false, + "ports": { + "3234/tcp": 3234, + "8234/tcp": 8234 + }, + "map": [ + "config:rw", + "ssl" + ], + "options": { + "log_level": "info", + "ssl": true, + "certfile": "fullchain.pem", + "keyfile": "privkey.pem", + "config_file": "home-panel-config.json" + }, + "schema": { + "log_level": "match(^(trace|debug|info|notice|warning|error|fatal)$)", + "ssl": "bool", + "certfile": "str", + "keyfile": "str", + "config_file": "str" + }, + "environment": { + "LOG_FORMAT": "{LEVEL}: {MESSAGE}" + } +} diff --git a/home-panel/icon.png b/home-panel/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..bfa6add331567e55c6bd7c5b174597d06934465b GIT binary patch literal 11188 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 literal 0 HcmV?d00001 diff --git a/home-panel/logo.png b/home-panel/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ab4a2c4a5e06b4c5e8623a7ebf202991704fdda9 GIT binary patch literal 29594 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 Q`vZCLOzkOB?&Z7x2h{gl>i_@% literal 0 HcmV?d00001 diff --git a/home-panel/rootfs/etc/cont-init.d/10-config.sh b/home-panel/rootfs/etc/cont-init.d/10-config.sh new file mode 100644 index 0000000..4357d06 --- /dev/null +++ b/home-panel/rootfs/etc/cont-init.d/10-config.sh @@ -0,0 +1,19 @@ +#!/usr/bin/with-contenv bash +# ============================================================================== +# Community Hass.io Add-ons: Home Panel +# This copies the configs to their respective locations +# ============================================================================== +# shellcheck disable=SC1091 +source /usr/lib/hassio-addons/base.sh + +config_file="/config/$(hass.config.get 'config_file')" + +if [ ! -f "$config_file" ]; then + hass.log.info "Config file does not exist. Creating.." + cp /etc/home-panel/home-panel-config.default.json "$config_file" + hass.log.info "You should now edit this file, then restart the addon." +fi + +hass.log.info "Copy config.." + +cp "$config_file" /usr/src/api/files/config.json diff --git a/home-panel/rootfs/etc/cont-init.d/20-nginx.sh b/home-panel/rootfs/etc/cont-init.d/20-nginx.sh new file mode 100644 index 0000000..c1e0396 --- /dev/null +++ b/home-panel/rootfs/etc/cont-init.d/20-nginx.sh @@ -0,0 +1,38 @@ +#!/usr/bin/with-contenv bash +# ============================================================================== +# Community Hass.io Add-ons: Home Panel +# This copies the nginx configs to their respective locations +# ============================================================================== +# shellcheck disable=SC1091 +source /usr/lib/hassio-addons/base.sh + +certfile="/ssl/$(hass.config.get 'certfile')" +keyfile="/ssl/$(hass.config.get 'keyfile')" + +if [ -f "$certfile" ]; then + hass.log.info "Copy enabled SSL nginx config" + echo "server { + listen 8234 ssl http2 default_server; + listen [::]:8234 ssl http2 default_server; + root /usr/share/nginx/html; + index index.html; + server_name 172.0.0.1; + ssl_certificate ${certfile}; + ssl_certificate_key ${keyfile}; + location / { + try_files \$uri /index.html; + } + }" > /etc/nginx/conf.d/default.conf; +else + hass.log.info "Copy disabled SSL nginx config" + echo "server { + listen 8234 default_server; + listen [::]:8234 default_server; + root /usr/share/nginx/html; + index index.html; + server_name 172.0.0.1; + location / { + try_files \$uri /index.html; + } + }" > /etc/nginx/conf.d/default.conf; +fi diff --git a/home-panel/rootfs/etc/cont-init.d/30-api.sh b/home-panel/rootfs/etc/cont-init.d/30-api.sh new file mode 100644 index 0000000..e84952a --- /dev/null +++ b/home-panel/rootfs/etc/cont-init.d/30-api.sh @@ -0,0 +1,18 @@ +#!/usr/bin/with-contenv bash +# ============================================================================== +# Community Hass.io Add-ons: Home Panel +# This copies the api files to their respective locations +# ============================================================================== +# shellcheck disable=SC1091 +source /usr/lib/hassio-addons/base.sh + +echo "REACT_APP_API_URL = $(hass.config.get 'api_url')" > /usr/src/app/.env.local + +certfile="/ssl/$(hass.config.get 'certfile')" +keyfile="/ssl/$(hass.config.get 'keyfile')" + +if [ -f "$certfile" ]; then + hass.log.info "Copy SSL certs to api directory" + cp "$certfile" /usr/src/api/fullchain.pem + cp "$keyfile" /usr/src/api/privkey.pem +fi diff --git a/home-panel/rootfs/etc/home-panel/home-panel-config.default.json b/home-panel/rootfs/etc/home-panel/home-panel-config.default.json new file mode 100644 index 0000000..59330cb --- /dev/null +++ b/home-panel/rootfs/etc/home-panel/home-panel-config.default.json @@ -0,0 +1,52 @@ +{ + "theme": {}, + "header": { + "left_outdoor_weather": { + "dark_sky_icon": "sensor.dark_sky_icon", + "condition": "sensor.pws_weather", + "data": [ + { + "entity_id": "sensor.pws_temp_c", + "unit_of_measurement": "°C" + }, + { + "entity_id": "sensor.pws_relative_humidity", + "unit_of_measurement": "%" + } + ] + }, + "right_indoor": [ + { + "label": "Living Room", + "data": [ + { + "entity_id": "sensor.dht22_01_temperature", + "unit_of_measurement": "°C" + }, + { + "entity_id": "sensor.dht22_01_humidity", + "unit_of_measurement": "%" + } + ] + } + ] + }, + "items": [ + { + "name": "Living Room", + "cards": [ + { + "entity_id": "light.tv_light" + } + ] + }, + { + "name": "Dining Room", + "cards": [ + { + "entity_id": "light.table_light" + } + ] + } + ] +} diff --git a/home-panel/rootfs/etc/services.d/api/finish b/home-panel/rootfs/etc/services.d/api/finish new file mode 100644 index 0000000..77ac620 --- /dev/null +++ b/home-panel/rootfs/etc/services.d/api/finish @@ -0,0 +1,9 @@ +#!/usr/bin/execlineb -S0 +# ============================================================================== +# Community Hass.io Add-ons: Home Panel +# Take down the S6 supervision tree when Home Panel fails +# ============================================================================== +if -n { s6-test $# -ne 0 } +if -n { s6-test ${1} -eq 256 } + +s6-svscanctl -t /var/run/s6/services diff --git a/home-panel/rootfs/etc/services.d/api/run b/home-panel/rootfs/etc/services.d/api/run new file mode 100644 index 0000000..617bd4e --- /dev/null +++ b/home-panel/rootfs/etc/services.d/api/run @@ -0,0 +1,14 @@ +#!/usr/bin/with-contenv bash +# ============================================================================== +# Community Hass.io Add-ons: Home Panel +# Starts server to serve the api +# ============================================================================== +# shellcheck disable=SC1091 +source /usr/lib/hassio-addons/base.sh + +hass.log.info "Run API.." + +# shellcheck disable=SC2164 +cd /usr/src/api + +node index.js diff --git a/home-panel/rootfs/etc/services.d/config/finish b/home-panel/rootfs/etc/services.d/config/finish new file mode 100644 index 0000000..77ac620 --- /dev/null +++ b/home-panel/rootfs/etc/services.d/config/finish @@ -0,0 +1,9 @@ +#!/usr/bin/execlineb -S0 +# ============================================================================== +# Community Hass.io Add-ons: Home Panel +# Take down the S6 supervision tree when Home Panel fails +# ============================================================================== +if -n { s6-test $# -ne 0 } +if -n { s6-test ${1} -eq 256 } + +s6-svscanctl -t /var/run/s6/services diff --git a/home-panel/rootfs/etc/services.d/config/run b/home-panel/rootfs/etc/services.d/config/run new file mode 100644 index 0000000..f785e99 --- /dev/null +++ b/home-panel/rootfs/etc/services.d/config/run @@ -0,0 +1,16 @@ +#!/usr/bin/with-contenv bash +# ============================================================================== +# Community Hass.io Add-ons: Home Panel +# Keeps the config file up to date +# ============================================================================== +# shellcheck disable=SC1091 +source /usr/lib/hassio-addons/base.sh + +config_file="/config/$(hass.config.get 'config_file')" + +# shellcheck disable=SC2162 +# shellcheck disable=SC2034 +inotifywait -m "$config_file" | while read file; do \ +hass.log.debug "Update Config.." \ +&& cp "$config_file" /usr/src/api/files/config.json; \ +done diff --git a/home-panel/rootfs/etc/services.d/nginx/finish b/home-panel/rootfs/etc/services.d/nginx/finish new file mode 100644 index 0000000..77ac620 --- /dev/null +++ b/home-panel/rootfs/etc/services.d/nginx/finish @@ -0,0 +1,9 @@ +#!/usr/bin/execlineb -S0 +# ============================================================================== +# Community Hass.io Add-ons: Home Panel +# Take down the S6 supervision tree when Home Panel fails +# ============================================================================== +if -n { s6-test $# -ne 0 } +if -n { s6-test ${1} -eq 256 } + +s6-svscanctl -t /var/run/s6/services diff --git a/home-panel/rootfs/etc/services.d/nginx/run b/home-panel/rootfs/etc/services.d/nginx/run new file mode 100644 index 0000000..42d73d8 --- /dev/null +++ b/home-panel/rootfs/etc/services.d/nginx/run @@ -0,0 +1,11 @@ +#!/usr/bin/with-contenv bash +# ============================================================================== +# Community Hass.io Add-ons: Home Panel +# Starts server to serve the webapp +# ============================================================================== +# shellcheck disable=SC1091 +source /usr/lib/hassio-addons/base.sh + +hass.log.info "Run nginx server.." + +nginx -g "daemon off;"