first commit

main
Ben 1 year ago
commit e5466c3aad

@ -0,0 +1,16 @@
include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI support for homeassistant
LUCI_PKGARCH:=all
LUCI_DEPENDS:=@(aarch64||arm||x86_64) +lsblk +luci-app-dockerman +luci-lib-taskd
define Package/luci-app-homeassistant/conffiles
/etc/config/homeassistant
endef
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

@ -0,0 +1,9 @@
module("luci.controller.homeassistant", package.seeall)
function index()
entry({"admin", "apps", "homeassistant"}, alias("admin", "apps", "homeassistant", "config"), _("Home Assistant"), 30).dependent = true
entry({"admin", "apps", "homeassistant", "config"}, cbi("homeassistant/config"), _("Config"), 10).leaf = true
entry({"admin", "apps", "homeassistant", "tool"}, form("homeassistant/tool"), _("Tool"), 30).leaf = true
entry({"admin", "apps", "homeassistant", "console"}, form("homeassistant/console"), _("Console"), 50).leaf = true
end

@ -0,0 +1,48 @@
--[[
LuCI - Lua Configuration Interface
]]--
local taskd = require "luci.model.tasks"
local homeassistant_model = require "luci.model.homeassistant"
local m, s, o
m = taskd.docker_map("homeassistant", "homeassistant", "/usr/libexec/apps/homeassistant.sh",
translate("Home Assistant"),
translate("Open source home automation that puts local control and privacy first. Powered by a worldwide community of tinkerers and DIY enthusiasts.")
.. translate("Official website:") .. ' <a href=\"https://www.home-assistant.io/\" target=\"_blank\">https://www.home-assistant.io/</a>')
s = m:section(SimpleSection, translate("Service Status"), translate("Home Assistant status:"))
s:append(Template("homeassistant/status"))
s = m:section(TypedSection, "homeassistant", translate("Setup"), translate("The following parameters will only take effect during installation or upgrade:"))
s.addremove=false
s.anonymous=true
o = s:option(Value, "image_name", translate("Image").."<b>*</b>")
o.rmempty = false
o.datatype = "string"
o:value("homeassistant/home-assistant:latest", "homeassistant/home-assistant:latest")
o:value("homeassistant/home-assistant:2023.3.3", "homeassistant/home-assistant:2023.3.3")
o:value("homeassistant/home-assistant:dev", "homeassistant/home-assistant:dev")
o:value("ghcr.io/home-assistant/home-assistant:stable", "ghcr.io/home-assistant/home-assistant:stable")
o:value("ghcr.io/home-assistant/home-assistant:2023.3.3", "ghcr.io/home-assistant/home-assistant:2023.3.3")
o.default = "homeassistant/home-assistant:latest"
local blocks = homeassistant_model.blocks()
local home = homeassistant_model.home()
o = s:option(Value, "config_path", translate("Config path").."<b>*</b>")
o.rmempty = false
o.datatype = "string"
local paths, default_path = homeassistant_model.find_paths(blocks, home, "Configs")
for _, val in pairs(paths) do
o:value(val, val)
end
o.default = default_path
o = s:option(Value, "time_zone", translate("Timezone"))
o.datatype = "string"
o:value("America/New_York", "America/New_York")
return m

@ -0,0 +1,116 @@
--[[
LuCI - Lua Configuration Interface
]]--
require "luci.util"
local docker = require "luci.model.docker"
local dk = docker.new()
local container_name = "homeassistant"
local m, s, o
local images, networks, container_info, res
res = dk.containers:inspect({name = container_name})
if res.code < 300 then
container_info = res.body
else
return
end
local cmd_docker = luci.util.exec("command -v docker"):match("^.+docker") or nil
local cmd_ttyd = luci.util.exec("command -v ttyd"):match("^.+ttyd") or nil
if cmd_docker and cmd_ttyd and container_info.State.Status == "running" then
local cmd = "/bin/bash"
local uid
m=SimpleForm("Console", "", translate("Only works in LAN"))
m.submit = false
m.reset = false
s = m:section(SimpleSection)
o = s:option(Value, "command", translate("Command"))
o:value("/bin/sh", "/bin/sh")
o:value("/bin/ash", "/bin/ash")
o:value("/bin/bash", "/bin/bash")
o.default = "/bin/bash"
o.forcewrite = true
o.write = function(self, section, value)
cmd = value
end
o = s:option(Value, "uid", translate("UID"))
o.forcewrite = true
o.write = function(self, section, value)
uid = value
end
o = s:option(Button, "connect")
o.render = function(self, section, scope)
self.inputstyle = "add"
self.title = " "
self.inputtitle = translate("Connect")
Button.render(self, section, scope)
end
o.write = function(self, section)
local cmd_docker = luci.util.exec("command -v docker"):match("^.+docker") or nil
local cmd_ttyd = luci.util.exec("command -v ttyd"):match("^.+ttyd") or nil
if not cmd_docker or not cmd_ttyd or cmd_docker:match("^%s+$") or cmd_ttyd:match("^%s+$")then
return
end
local pid = luci.util.trim(luci.util.exec("netstat -lnpt | grep :7682 | grep ttyd | tr -s ' ' | cut -d ' ' -f7 | cut -d'/' -f1"))
if pid and pid ~= "" then
luci.util.exec("kill -9 " .. pid)
end
local hosts
local uci = require "luci.model.uci".cursor()
local remote = uci:get_bool("dockerd", "globals", "remote_endpoint") or false
local host = nil
local port = nil
local socket = nil
if remote then
host = uci:get("dockerd", "globals", "remote_host") or nil
port = uci:get("dockerd", "globals", "remote_port") or nil
else
socket = uci:get("dockerd", "globals", "socket_path") or "/var/run/docker.sock"
end
if remote and host and port then
hosts = host .. ':'.. port
elseif socket then
hosts = socket
else
return
end
if uid and uid ~= "" then
uid = "-u " .. uid
else
uid = ""
end
local start_cmd = string.format('%s -d 2 --once -p 7682 %s -H "unix://%s" exec -it %s %s %s&', cmd_ttyd, cmd_docker, hosts, uid, container_name, cmd)
os.execute(start_cmd)
m.children[#m.children] = nil
s = m:section(SimpleSection)
o = s:option(DummyValue, "console")
o.container_id = container_id
o.template = container_name .. "/console"
end
else
m=SimpleForm("Console", "", translate("Home Assistant is not running"))
m.submit = false
m.reset = false
s = m:section(SimpleSection)
end
return m

@ -0,0 +1,41 @@
--[[
LuCI - Lua Configuration Interface
]]--
local http = require 'luci.http'
m=SimpleForm("Tools")
m.submit = false
m.reset = false
s = m:section(SimpleSection)
o = s:option(Value, "action", translate("Action").."<b>*</b>")
o.rmempty = false
o.datatype = "string"
o:value("hacs-install", "hacs-install")
o.default = "hacs-install"
local t=Template("homeassistant/tool")
m:append(t)
local btn_do = s:option(Button, "_do")
btn_do.render = function(self, section, scope)
self.inputstyle = "add"
self.title = " "
self.inputtitle = translate("Execute")
Button.render(self, section, scope)
end
btn_do.write = function(self, section, value)
local action = m:get(section, "action")
if action == "hacs-install" then
local cmd = string.format("/usr/libexec/apps/homeassistant.sh %s", action)
cmd = "/etc/init.d/tasks task_add homeassistant " .. luci.util.shellquote(cmd) .. " >/dev/null 2>&1"
os.execute(cmd)
t.show_log_taskid = "homeassistant"
end
end
return m

@ -0,0 +1,55 @@
local util = require "luci.util"
local jsonc = require "luci.jsonc"
local emby = {}
emby.blocks = function()
local f = io.popen("lsblk -s -f -b -o NAME,FSSIZE,MOUNTPOINT --json", "r")
local vals = {}
if f then
local ret = f:read("*all")
f:close()
local obj = jsonc.parse(ret)
for _, val in pairs(obj["blockdevices"]) do
local fsize = val["fssize"]
if fsize ~= nil and string.len(fsize) > 10 and val["mountpoint"] then
-- fsize > 1G
vals[#vals+1] = val["mountpoint"]
end
end
end
return vals
end
emby.home = function()
local uci = require "luci.model.uci".cursor()
local home_dirs = {}
home_dirs["main_dir"] = uci:get_first("quickstart", "main", "main_dir", "/root")
home_dirs["Configs"] = uci:get_first("quickstart", "main", "conf_dir", home_dirs["main_dir"].."/Configs")
home_dirs["Public"] = uci:get_first("quickstart", "main", "pub_dir", home_dirs["main_dir"].."/Public")
home_dirs["Downloads"] = uci:get_first("quickstart", "main", "dl_dir", home_dirs["Public"].."/Downloads")
home_dirs["Caches"] = uci:get_first("quickstart", "main", "tmp_dir", home_dirs["main_dir"].."/Caches")
return home_dirs
end
emby.find_paths = function(blocks, home_dirs, path_name)
local default_path = ''
local configs = {}
default_path = home_dirs[path_name] .. "/HomeAssistant"
if #blocks == 0 then
table.insert(configs, default_path)
else
for _, val in pairs(blocks) do
table.insert(configs, val .. "/" .. path_name .. "/HomeAssistant")
end
local without_conf_dir = "/root/" .. path_name .. "/HomeAssistant"
if default_path == without_conf_dir then
default_path = configs[1]
end
end
return configs, default_path
end
return emby

@ -0,0 +1,6 @@
<div class="cbi-map">
<iframe id="terminal" style="width: 100%; min-height: 600px; border: none; border-radius: 3px;"></iframe>
</div>
<script type="text/javascript">
document.getElementById("terminal").src = "http://" + window.location.hostname + ":7682";
</script>

@ -0,0 +1,31 @@
<%
local util = require "luci.util"
local container_status = util.trim(util.exec("/usr/libexec/apps/homeassistant.sh status"))
local container_install = (string.len(container_status) > 0)
local container_running = container_status == "running"
-%>
<div class="cbi-value">
<label class="cbi-value-title"><%:Status%></label>
<div class="cbi-value-field">
<% if container_running then %>
<button class="cbi-button cbi-button-success" disabled="true"><%:Home Assistant is running%></button>
<% else %>
<button class="cbi-button cbi-button-negative" disabled="true"><%:Home Assistant is not running%></button>
<% end %>
</div>
</div>
<%
if container_running then
local port=util.trim(util.exec("/usr/libexec/apps/homeassistant.sh port"))
if port == "" then
port="8123"
end
-%>
<div class="cbi-value cbi-value-last">
<label class="cbi-value-title">&nbsp;</label>
<div class="cbi-value-field">
<input type="button" class="btn cbi-button cbi-button-apply" name="start" value="<%:Open the Home Assistant%>" onclick="window.open('http://'+location.hostname+':<%=port%>/', '_blank')">
</div>
</div>
<% end %>

@ -0,0 +1,11 @@
<%+tasks/embed%>
<script>
window.addEventListener("load", function(){
const taskd = window.taskd;
<% if self.show_log_taskid then -%>
taskd.show_log("<%=self.show_log_taskid%>");
<%- end %>
});
</script>

@ -0,0 +1,51 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
msgid "Official website:"
msgstr "官方网站:"
msgid "Open source home automation that puts local control and privacy first. Powered by a worldwide community of tinkerers and DIY enthusiasts."
msgstr "将本地控制和隐私放在首位的开源家庭自动化,由全世界 DIY 爱好者组成的社区驱动。"
msgid "Config path"
msgstr "配置文件路径"
msgid "Service Status"
msgstr "服务状态"
msgid "Home Assistant status:"
msgstr "Home Assistant 的状态信息如下:"
msgid "Setup"
msgstr "安装配置"
msgid "The following parameters will only take effect during installation or upgrade:"
msgstr "以下参数只在安装或者升级时才会生效:"
msgid "Status"
msgstr "状态"
msgid "Home Assistant is running"
msgstr "Home Assistant 运行中"
msgid "Home Assistant is not running"
msgstr "Home Assistant 未运行"
msgid "Open the Home Assistant"
msgstr "打开 Home Assistant"
msgid "Tool"
msgstr "操作"
msgid "Console"
msgstr "控制台"
msgid "Only works in LAN"
msgstr "只在内网环境下工作。"
msgid "Execute"
msgstr "执行"
msgid "Timezone"
msgstr "时区"

@ -0,0 +1 @@
zh-cn

@ -0,0 +1,4 @@
config homeassistant
option 'config_path' ''
option 'image_name' 'homeassistant/home-assistant:latest'
option 'time_zone' ''

@ -0,0 +1,103 @@
#!/bin/sh
ACTION=${1}
shift 1
do_install() {
local config=`uci get homeassistant.@homeassistant[0].config_path 2>/dev/null`
local IMAGE_NAME=`uci get homeassistant.@homeassistant[0].image_name 2>/dev/null`
local tz=`uci get homeassistant.@homeassistant[0].time_zone 2>/dev/null`
if [ -z "$config" ]; then
echo "config path is empty!"
exit 1
fi
echo "docker pull ${IMAGE_NAME}"
docker pull ${IMAGE_NAME}
docker rm -f homeassistant
local cmd="docker run --restart=unless-stopped -d \
-v \"$config:/config\" \
--privileged \
--network=host \
--dns=1.1.1.1 "
#Add link to shortcutmenu
# Get our local LAN IP Address
LAN_IP=$(uci get network.lan.ipaddr)
# Strip trailing network mask
LAN_IP="${LAN_IP%/*}"
# Add a new list option to the "shortcutmenu" configuration file
uci add shortcutmenu lists
uci set shortcutmenu.@lists[-1].webname="$IMAGE_NAME"
uci set shortcutmenu.@lists[-1].weburl="$LAN_IP:8123"
uci set shortcutmenu.@lists[-1].webpath="/"
uci commit shortcutmenu
if [ -z "$tz" ]; then
tz="`uci get system.@system[0].zonename`"
fi
[ -z "$tz" ] || cmd="$cmd -e TZ=$tz"
cmd="$cmd --name homeassistant \"$IMAGE_NAME\""
echo "$cmd"
eval "$cmd"
RET=$?
if [ "$RET" = "0" ]; then
echo "Wait 10 seconds for homeassistant boot..."
sleep 10
do_hacs_install
fi
}
do_hacs_install() {
echo "Install HACS"
echo "rm -f custom_components/hacs.zip config/custom_components/hacs.zip ; wget -O - https://get.hacs.xyz | bash -" | docker exec -i homeassistant bash -
sleep 3
echo "restart homeassistant"
docker restart homeassistant
return 0
}
usage() {
echo "usage: $0 sub-command"
echo "where sub-command is one of:"
echo " install Install the homeassistant"
echo " upgrade Upgrade the homeassistant"
echo " rm/start/stop/restart Remove/Start/Stop/Restart the homeassistant"
echo " status Home Assistant status"
echo " port Home Assistant port"
}
case ${ACTION} in
"install")
do_install
;;
"upgrade")
do_install
;;
"rm")
docker rm -f homeassistant
;;
"start" | "stop" | "restart")
docker ${ACTION} homeassistant
;;
"status")
docker ps --all -f 'name=homeassistant' --format '{{.State}}'
;;
"port")
docker ps --all -f 'name=homeassistant' --format '{{.Ports}}' | grep -om1 '0.0.0.0:[0-9]*' | sed 's/0.0.0.0://'
;;
"hacs-install")
do_hacs_install
;;
*)
usage
exit 1
;;
esac

@ -0,0 +1,11 @@
{
"luci-app-homeassistant": {
"description": "Grant UCI access for luci-app-homeassistant",
"read": {
"uci": [ "homeassistant" ]
},
"write": {
"uci": [ "homeassistant" ]
}
}
}
Loading…
Cancel
Save