Skip to content

Latest commit

 

History

History
430 lines (310 loc) · 15 KB

IGW5000.en.md

File metadata and controls

430 lines (310 loc) · 15 KB

Repurposing Movistar Home

as a Home Assistant dashboard panel.

This document is only intended for the model IGW-5000A2BKMP-I v2 with an Intel x86 CPU. For the model RG3205W with a Qualcomm arm64 SoC, please refer to RG3205W.en.md.

🇪🇸 Versión en castellano

Research notes

HELP NEEDED

I dumped the original Android-x86 firmware from flash, but it failed to boot after I wrote it back in, and the /data partition was encrypted and I couldn't find a way to decrypt it.

Contributions to the repository are very welcomed if you've got any discoveries; or if you have a Movistar Home not in use and willing to help this project, please join our Telegram group chat, much appreciated!

TODO list

  • Fix sound card driver (maybe ALSA configs)
  • Fix camera driver
  • Fix bluetooth driver
  • Fix reset button
  • Find a way to install Linux without disassembling nor soldering (maybe through easycwmp on port 7547)

Tech specs

CPU Intel Atom x5-Z8350 (4C4T) @ 1.44 GHz
RAM Hynix 2 GB DDR3 ECC @ 1600 MHz
Storage Kingston TB2816 16 GB eMMC
Screen 8-inch 1280x800 with Goodix I2C touch screen
Wi-Fi & Bluetooth Realtek RTL8822BE
Sound card Realtek RT5672
Speakers 2 x 5 W (SPL 87 dB @ 1 W | 1 m)
Microphones 4 omnidirectional microphones with dedicated DSP
Camera OMNIVISION OV2680 with 2 megapixels
Dimensions 21.2 x 23.5 x 12.2 cm (height x width x depth)
Weight 1.1 kg

Driver status

As in the latest Manjaro XFCE 24.0.2 with 6.9.3-3 kernel, on June 19, 2024:

Device Driver Status
Touch screen goodix_ts OK
Wi-Fi rtw88_8822be OK
Bluetooth rtw88_8822be Not working
Sound card snd_soc_sst_cht_bsw_rt5672 Not working
Camera atomisp Not working in kernel 5.15, unavailable in kernel 6.2+

Linux installation

Disassembling

Disassemble the device, it has 10 snap-fits under the back panel edges, be careful not to damage them; then 8 screws under the panel, and 4 screws hidden under the rubber strip at the bottom of the device.

Locate the unpopulated micro USB port on the left edge of the motherboard:

inside-with-usb-port-location

Solder a micro USB female connector and connect an OTG adapter cable; or just solder a cable with a standard USB-A female connector to it, then short the fourth pin (or the ID pad) to the ground (GND, the fifth pin), making the device function as an OTG host.

Here is an example for soldering a USB-A female connector:

igw5000-usb-port-connection-1

Flash a USB drive with your favorite Linux distro, I recommend using Xfce desktop environment considering the Movistar Home only has 2 GB RAM.

Connect a keyboard and the drive to a USB hub and connect it to Movistar Home. Power it up while pressing the F2 key, it will boot into BIOS setup, navigate to the last tab (Save & Exit), select your USB drive (should be something like UEFI: USB, Partition 1) in the Boot Override menu, press Enter key to boot it.

bios

Install your Linux distro as usual, it might be necessary to include non-free drivers.

It's recommended to set up the OpenSSH server before unsoldering the USB connector and reassembling the device, for possible future maintenance.

Configurations

The following configurations were made for Manjaro with XFCE and may need some modifications for other distros or desktop environments.

Fix screen rotation

Install the driver xf86-video-intel with the command sudo pacman -S xf86-video-intel.

Create file /etc/X11/xorg.conf.d/20-monitor.conf with the following content:

Section "Monitor"
    Identifier    "DSI1"
    Option        "Rotate" "right"
    Option        "DPMS" "true"
EndSection

Section "ServerFlags"
    Option        "StandbyTime" "0"
    Option        "SuspendTime" "0"
    Option        "OffTime"     "0"
EndSection

In Xfce's display settings, adjust the scaling to your liking, I found 0.8x the most suitable for this screen (1024x640).

Fix touch screen

For some reason the touch screen won't work at all unless it's soft rebooted once, in dmesg the driver says "Goodix-TS i2c-GDIX1001:00: Invalid config (0, 0, 0), using defaults".

Create file /etc/systemd/system/fix-touchscreen.service with the following content:

[Unit]
Description=Fix touchscreen

[Service]
Type=oneshot
ExecStart=sh -c 'dmesg | grep -q " Goodix-TS .*: Invalid config " && reboot now || exit 0'

[Install]
WantedBy=multi-user.target

Then execute sudo systemctl daemon-reload && sudo systemctl enable fix-touchscreen.service to make it run at startup.

To fix rotation, create file /etc/X11/xorg.conf.d/30-touchscreen.conf with the following content:

Section "InputClass"
    Identifier      "calibration"
    MatchProduct    "Goodix Capacitive TouchScreen"
    Option          "TransformationMatrix" "0 1 0 -1 0 1 0 0 1"
EndSection

Fix touch control in Firefox

Source: Firefox/Tweaks - ArchWiki

Open Firefox and access about:config, search for dom.w3c_touch_events.enabled and make sure it's either set to 1 (enabled) or 2 (default, auto-detect).

Add MOZ_USE_XINPUT2 DEFAULT=1 to /etc/security/pam_env.conf.

Auto backlight dimming

Modify file /etc/mkinitcpio.conf to include i915 and pwm-lpss-platform in the MODULES array as below:

...
MODULES=(i915 pwm-lpss-platform)
...

Then execute sudo mkinitcpio -P to regenerate the initramfs.

Create file /etc/X11/xorg.conf.d/10-intel.conf with the following content:

Section "Device"
    Identifier    "Intel Graphics"
    Driver        "intel"
    Option        "AccelMethod" "sna"
    Option        "TearFree"    "true"
    Option        "Backlight"   "intel_backlight"
EndSection

Open Xfce's Power Manager, switch to Display tab, and adjust the Brightness reduction settings. I personally set it to reduce to 20% after 90 seconds of inactivity.

Remember also to disable the auto suspension/shutdown from there.

Create file /etc/udev/rules.d/backlight.rules with the following content:

ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="intel_backlight", RUN+="/bin/chgrp video $sys$devpath/brightness", RUN+="/bin/chmod g+w $sys$devpath/brightness", ATTR{brightness}="100"

And better to disable the systemd-backlight service with sudo systemctl mask systemd-backlight@backlight\:intel_backlight.service, to prevent it from interfering.

Virtual keyboard

Install Onboard with sudo pacman -S onboard, open Xfce's Session and Startup settings, switch to Application Autostart tab, find and enable Onboard (Flexible onscreen keyboard).

After rebooting, open Onboard's settings and adjust them to your liking.

Hide mouse cursor

Install unclutter with sudo pacman -S unclutter.

Create file ~/.config/autostart/hide-cursor.desktop with the following content:

[Desktop Entry]
Encoding=UTF-8
Version=0.9.4
Type=Application
Name=Hide Cursor
Comment=Hide mourse cursor
Exec=unclutter --hide-on-touch
OnlyShowIn=XFCE;
RunHook=0
StartupNotify=false
Terminal=false
Hidden=false

Home Assistant dashboard

Create file ~/.config/autostart/HASS.desktop with the following content:

[Desktop Entry]
Encoding=UTF-8
Version=0.9.4
Type=Application
Name=HASS Dashboard
Comment=Run HASS dashboard in Firefox kiosk
Exec=firefox -kiosk -url 'https://your.hass.url'
OnlyShowIn=XFCE;
RunHook=0
StartupNotify=false
Terminal=false
Hidden=false

This will run Firefox in kiosk mode at startup, which you can only exit by pressing Alt+F4 or using kill command over SSH.

Control display state from Home Assistant

Tip

As mentioned in ArchLinux Wiki, for xset to be able to control DPMS, you need to disable:

  1. Screen dimming in Xfce's Power Manager.
  2. Xfce's XScreenSaver.

Create file ~/panel_server.py with the following content:

#!/usr/bin/env python3
import logging
import os
from subprocess import run
from time import sleep

from flask import Flask, request
from werkzeug.wrappers import Request, Response

TOKEN = os.environ.get('TOKEN', '')


class middleware():
    def __init__(self, app):
        self.app = app

    def __call__(self, env, start_resp):
        request = Request(env)
        if TOKEN != '' and request.headers.get('Authorization') != f'Bearer {TOKEN}':
            res = Response('Unauthorized', mimetype='text/plain', status=401)
            return res(env, start_resp)
        return self.app(env, start_resp)


app = Flask(__name__)
app.wsgi_app = middleware(app.wsgi_app)
log = logging.getLogger('werkzeug')
log.setLevel(logging.ERROR)


@app.route('/display/state', methods=['GET'])
def get_display_state():
    cmd = f"xset -display :0.0 q | grep '^  Monitor is' | awk '{{print $NF}}'"
    state = run(cmd, shell=True, capture_output=True).stdout.decode().strip()
    if state == 'On':
        return 'ON', 200
    elif state == 'Off':
        return 'OFF', 200
    else:
        return f'Unknown state "{state}"', 500


@app.route('/display/state', methods=['POST'])
def set_display_state():
    req_body = request.get_data().decode()
    if req_body == 'OFF':
        cmd = f'xset -display :0.0 dpms force off'
    elif req_body == 'ON':
        cmd = f'xset -display :0.0 dpms force on'
    else:
        return 'Bad Request', 400

    ret = run(cmd, shell=True).returncode
    if ret == 0:
        return req_body, 200
    else:
        return f'Command returned {ret}', 500


def init_display():
    while True:
        out = run(f"xset -display :0.0 q | grep '^  DPMS is '", shell=True, capture_output=True).stdout.decode()
        if 'Disabled' in out or 'Enabled' in out:
            break
        sleep(3)
    ret = run(f'xset -display :0.0 dpms force on', shell=True).returncode
    if ret != 0:
        print(f'Failed to turn on display: command returned {ret}')
        exit(ret)


if __name__ == '__main__':
    init_display()

    app.run(host=os.environ.get('HOST', '0.0.0.0'), port=os.environ.get('PORT', 8080))

Run sudo pacman -S python-flask to install Flask.

Create file ~/.config/systemd/user/panelserver.service with the following content:

[Unit]
Description=Panel Server
After=network-online.target nss-lookup.target graphical-session.target

[Service]
Environment="TOKEN=aa83720a-0bc1-4d5b-82fc-bf27a6682aa4"  # replace it with your secret token
NoNewPrivileges=true
ExecStart=/usr/bin/python3 /home/panel/panel_server.py  # replace it with your actual path
Restart=always

[Install]
WantedBy=default.target

Then execute systemctl --user daemon-reload && systemctl --user enable --now panelserver.service to make it run at startup.

Create a RESTful switch in your Home Assistant's YAML config like:

- platform: rest
  name: Panel Display
  unique_id: panel_display
  resource: http://panel:8080/display/state  # replace `panel` with your panel's hostname or IP address
  body_on: 'ON'
  body_off: 'OFF'
  is_on_template: '{{ value == "ON" }}'
  headers:
    Authorization: Bearer aa83720a-0bc1-4d5b-82fc-bf27a6682aa4  # replace it with your secret token (after `Bearer `)
  verify_ssl: false
  icon: mdi:tablet-dashboard

Reload your Home Assistant instance, use Developer Tools to test the switch and sensor.

Then you can use it in Automations, e.g., turn it off when you go to sleep at night and turn it back on when you get up in the morning.

Prevent screen burn-in

Since it will mostly be used to display a Home Assistant dashboard 24/7, it's very likely to get screen burn-in after some time, although it has an LCD screen.

To prevent that, I wrote a Python script to have it periodically flash several colors in full screen to refresh all the pixels, it also refreshes the browser tab at the same time, to prevent any possible stuck.

Caution

DO NOT USE this script if you or a family member has photosensitive epilepsy!

Create file /usr/bin/screensaver.py with the following content:

#!/usr/bin/env python3
import os
import threading
import tkinter as tk
from subprocess import run
from time import time

color_interval = int(os.environ.get('COLOR_INTERVAL', 300))  # milliseconds
total_time = int(os.environ.get('TOTAL_TIME', 10))  # seconds, exit after that
colors = ['red', 'green', 'blue', 'black', 'white']

root = tk.Tk()
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.overrideredirect(True)
root.attributes('-fullscreen', True)
canvas = tk.Canvas(root, width=w, height=h, background='black', highlightthickness=0)
canvas.pack()
canvas.focus_set()
canvas.bind('<Button-1>', lambda _: root.destroy())  # exit on touch

color_index = 0


def show_color():
    global color_index
    if time() - time_start > total_time:
        root.destroy()
        return
    canvas.configure(background=colors[color_index])
    color_index = (color_index + 1) % len(colors)
    root.after(color_interval, show_color)


def refresh_browser(window_class: str):
    window_id = run(f'xdotool search --onlyvisible --class "{window_class}" | head -1',
                    shell=True, capture_output=True).stdout.decode().strip()
    ret = run(f'xdotool windowactivate {window_id}', shell=True).returncode
    if ret != 0:
        print(f'Failed to activate window {window_id}')
    ret = run(f'xdotool key F5', shell=True).returncode
    if ret != 0:
        print(f'Failed to send F5 key to window {window_id}')


# refresh browser window
browser_window_class = os.environ.get('BROWSER_WINDOW_CLASS', '')
if browser_window_class:
    refresh_thread = threading.Thread(target=refresh_browser, args=(browser_window_class,))
    refresh_thread.start()
# screensaver
time_start = time()
show_color()
root.mainloop()

Install the required packages with sudo pacman -S tk xdotool, run command sudo chmod +x /usr/bin/screensaver.py to make it executable, then run command crontab -e and add a cron job as following, which will run the script every hour:

0 * * * *	DISPLAY=:0 COLOR_INTERVAL=300 TOTAL_TIME=10 BROWSER_WINDOW_CLASS="firefox" /usr/bin/python3 /usr/bin/screensaver.py

Adjust the two environment variables COLOR_INTERVAL and TOTAL_TIME to your liking, with a TOTAL_TIME of 10 it will be running for 10 seconds. If you need to stop it immediately, just touch the screen.

If you use another browser (e.g., chromium), change the value of BROWSER_WINDOW_CLASS accordingly; if you don't want to refresh the browser tab, make it empty (BROWSER_WINDOW_CLASS="").