Executando verificação de segurança...
14

Transformei o meu Fire TV Stick em um servidor WOL com Go

Motivação

Recentemente eu fiquei curioso sobre como a internet das coisas funciona e como eu desenvolveria algumas soluções, foi ai que pensei em criar uma forma de ligar meu PC de fora de casa.
Sim eu sei, a Alexa possui essa skill (mesmo que seja bugada), mas e se fosse para você criar, como o faria?

Otimização de recursos de hardware e software

Eu comecei a revisar as possibilidades, e então eu encontrei 3 possibilidades iniciais:

  • Fire TV Stick (que utilizo na minha TV)
  • Notebook antigo
  • Roteador com OpenWrt

Então eu comecei a investigar a possibilidade de utilizar o Fire TV.

Eu decidi utilizar o Go porque eu já estava arranjando uma desculpa para testar a linguagem já faz um tempo, a minha pergunta após o uso dela foi: por que não utilizei antes?

Eu utilizo muito node.js e .NET no dia a dia, mas ambos em comparação ao Go perdem em um ponto importante: footprint enxuto.

  • .NET
    • Footprint pode ser pequeno para .NET Framework 4.8, mas aqui é Windows Based
    • Há problemas de compilação cruzada e seu footprint com .NET 8, mas não vou adentrar muito nesse assunto pois não é o objetivo
  • Node.js
    • Lindo uso no dia a dia, funciona muito bem no Termux com arch ARM, inclusive utilizo muito no meu celular com Termux também
    • Uso de memória excessivo para pequenas operações
    • Footprint grande pois depende do binário do Node.js

Implementação

Primeiramente, gostaria de reconsiderar que o Fire TV Stick nunca desliga de fato, ele gerencia os app's para controle de memória e de energia, mas sempre se mantém ativo.
Você mesmo pode fazer este teste realizando o ping do ip na rede, caso possua um.

Estrutura da solução

  • Termux no FireTV (leve e lhe dá acesso ao Linux capado)
    • Habilitar via terminal: $ termux-wake-lock
      • Para forçar com que o Termux não perca prioridade na CPU (isso não afeta o uso do FireTV)
    • Projeto em GO
      • Inicia um server http para realizar as operações remotas
        • Teste de ping (não vi tanta utilidade, então eu removi)
        • Chamada de execução do processo de WOL para ligar o computador
          • Aqui é possível implementar via biblioteca no GO, mas ai me bateu a preguiça pois fazer com a chamada do serviço (binário) estava mais na mão e funciona igual.
      • Faz a chamada para um SSH client with reverse tunneling com NGROK
        • Faz o espelhamento da porta do server http para o Ngrok
        • Aqui eu tive que incluir na plataforma do Ngrok a chave pública gerada que você utiliza para conexões SSH
  • Ativação do Wake on Lan no computador
  • AnyDesk para acesso remoto (esse me atende bem, mas com o pc ligado as possibilidades exponenciam de uma maneira muito maior..)

Código

Controle da execução princial:

// main.go
package main

import (
        "fmt"
        "homec/connection"
        "homec/handlers"
        "net/http"
        "os"
)

func main() {
        go connection.LocalhostRun()
        portService := fmt.Sprintf("%d", connection.PORT_SERVICE)

        http.HandleFunc("/wake-pc", handlers.HandlerWakePc)
        http.HandleFunc("/ping-pc", handlers.HandlerPingPc)
        http.HandleFunc("/test", handlers.HandlerTest)
        http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
                http.Redirect(w, r, "/test", http.StatusSeeOther)
        })

        if err := http.ListenAndServe("localhost:"+portService, nil); err != nil {
                fmt.Println("Erro ao iniciar o servidor:", err)
                os.Exit(1)
        }
}

A comunicação com o serviço do Ngrok:

// connection/localhostrun.go
package connection

import (
        "bufio"
        "context"
        "fmt"
        "os/exec"
        "strings"
        "time"
)

var CountManyConnects int = 0
var PORT_SERVICE int = 8042

func LocalhostRun() {
	for {
		portService := fmt.Sprintf("%d", PORT_SERVICE)
		cmd := exec.Command("ssh", "-R", "0:localhost:"+portService, "[email protected]", "http")
		connected := false

		stdout, _ := cmd.StdoutPipe()
		// stderr, _ := cmd.StderrPipe()

		CountManyConnects++;
		if err := cmd.Start(); err != nil {
			fmt.Println("Erro ao iniciar o comando:", err)
			connected = false
		} else {
			connected = true
		}


		cmd.Wait()

		if connected {
			fmt.Println("SSH encerrado...")
			time.Sleep(1 * time.Second)
		} else {
			fmt.Println("Nova tentativa SSH encerrada...")
			time.Sleep(2 * time.Second)
		}
	}
}

A implementação com o pacote wol do Termux no endpoint /wake-pc (instalação com pkg install wol):

// handlers/wake-pc.go
package handlers

import (
        "net/http"
        "os/exec"
        "strings"
)

func HandlerWakePc(w http.ResponseWriter, r *http.Request) {
        if r.Method != "GET" {
                w.WriteHeader(http.StatusMethodNotAllowed)
                return
        }

        cmd := exec.Command("wol", "00:00:00:00:00:00")
        output, err := cmd.CombinedOutput()
        if err != nil {
                w.WriteHeader(http.StatusBadRequest)
                w.Write([]byte("It was not possible to wake the device"))
                return
        }

        if !strings.Contains(string(output), "Waking up") {
                w.WriteHeader(http.StatusBadRequest)
                w.Write([]byte("It was not possible to wake the device"))
                return
        }

        w.WriteHeader(http.StatusOK)
}

Abaixo o handler do endpoint /test, coloquei poucas informações somente para testar se o serviço está comunicando:

// handlers/test.go
package handlers

import (
        "fmt"
        "homec/connection"
        "net/http"
)

func HandlerTest(w http.ResponseWriter, r *http.Request) {
        if r.Method != "GET" {
                w.WriteHeader(http.StatusMethodNotAllowed)
                return
        }

        w.WriteHeader(http.StatusOK)
        w.Write([]byte("Ok!\n"))
        w.Write([]byte(fmt.Sprintf("CountManyConnects: %d", connection.CountManyConnects)))
}

Ressalvas importantes

Problemas na compilação cruzada

Utilizando o Windows 11 não foi tão difícil compilar para arm7 (arquitetura do FireTV), o problema foi que de alguma forma o comportamento não foi o mesmo. Tive problemas com a parte de comunicação e DNS, nada novo aqui, já encontrei esse problemas outras vezes. O problema é que a implementação do Termux não é exatamente igual a um Linux padrão, o projeto possui diversas modificações para tornar o projeto possível.

Qual foi a solução? compilei o projeto diretamente no FireTV.

Um pouco de SSH, SCP e poucos comandos depois o projeto já estava pronto.

O gadget não foi projetado para uso intenso

Além de ocupar pouco espaço, o Fire TV Stick possui pouca memória e processamento, então aqui a escolha do Go foi primordial para a efetividade do projeto.

É importante evitar disparar muitos comandos ou intensificar o uso da CPU e RAM para não crashar o app:
~ $ free -h

               total        used        free      shared  buff/cache   available
Mem:           899Mi       548Mi        48Mi       0.0Ki       302Mi       269Mi
Swap:          383Mi       251Mi       132Mi

Configuração inicial do Termux no Fire TV Stick

Eu precisei baixar um app Downloader, habilitar nas configurações para que esse app instale aplicativos e então, instalar o Termux.

Com o Termux em mãos, eu precisei instalar o OpenSSH com SSHD, para iniciar o SSHD (é possível iniciar junto com o terminal para evitar a input do comando caso precise reiniciar).

É simplesmente inviável utilizar terminal pelo controle da TV kkkk

Não contempla quedas de energia

Infelizmente não consegui configurar o Termux:Boot no Fire TV, mas creio que isso seja possível. Até lá, toda vez que ocorre quedas de energia o serviço fica fora pois o Fire TV não faz o Reboot (pelo menos o meu não faz).

Mas há uma possível solução, há algumas placas mães que tem a possibilidade de na queda de energia ela automaticamente bootar, é uma opção, mesmo assim não resolve o problema da inicialização do serviço

Conclusão

Foi um bom teste para avaliar Go e os limites do Fire TV Stick.

Agora eu quero testar o Termux em um SmartWatch com Android, embora as reclamações de uso de bateria nesse gadget, vale a pena testar o que dá para fazer nele kkk
Preciso de um pouco de estudo para entender se isso é possível.

Outro ponto importante é que já subestimei o Termux, mas a grande verdade é que você não precisa de acesso Root para a maior parte das coisas, pelo menos eu não precisei.

Algumas outras implementações que consegui com o Termux:

  • Syncar o Obsidian do celular com multiplos devices
  • Acessar o shell do celular de qualquer lugar com Ngrok (e consome pouca internet)
  • Utilizar o code-server (VsCode para servers) para editar projetos no celular (somente por curiosidade, mas é possível fazer)

Tem mais coisa que não lembro agora, é isso!

Carregando publicação patrocinada...
2

o termux, mesmo que seja limitado em alguns aspectos, com criatividade muitos projetos podem se beneficiar do uso do mesmo; eu já utilizei o termux no meu celular para instalar o LunarVim e escrever alguns scripts durante as aulas, era divertido, só ligar um teclado e começar a codar.

seu projeto me fez lembrar da existência de um raspberry model b que tá guardado na gaveta do meu quarto, estou pensando no que fazer com ele, recentemente cancelei um serviço de armazenamento em nuvem e essa era a desculpa que eu precisava para começar a brincar com ele, ainda tô pesquisando a respeito desse assunto e separando os dispositivos de armazenamento que vou utilizar, acredito que será um projeto bem divertido.

1
2

Fera... d+! porém eu particularmente não usaria a fire tv para isso. Usaria uma esp32 com o protocolo mqtt... ou até mesmo uma esp8266 ligada diretamente no jumper de power switch da placa mãe...

1

Caraca! não conhecia Ngrok haha.

Seu artigo foi muito bom pra mim. Tenho um projeto de automação domestica e o Ngrok pode servir para alguma coisa.. sem falar que estou estudando o Go pra fazer isso e seu projeto deu uma inspirada nas minhas ideias.

1
1

Caraca, muito interessante. Parabéns pelo projeto. Sou iniciante ainda na computação, então não compreendi profundamente vários ponto, todavia, achei-os incríveis. Recentemente eu utilizei o Temux para controlar a minha IPTV via ADB, achei bem legal. Eu poderia fazer algumas automações interessantes com isso.

1