Giter Club home page Giter Club logo

ha-glinet4-integration's Introduction

ha-glinet4-integration

A HomeAssistant custom component for GL-inet routers that uses their API version 4.

Working - in alpha, breaking changes very likely.

Contributions are welcome, for ideas see the TODO list below or the various #TODOs in the code.

Features

  • Device tracker for devices connected directly or indirectly to a Gl-inet router.
    • Note, modern phones use MAC address randomisation when they connect to WiFi, you will need to disable this for your home wifi only on android and iphone
  • Control all configured wireguard clients with a switch.

Installation

  1. Create a new folder in config/custom_components called glinet
  2. Copy manually, or clone the files in this repo into that folder git clone https://github.com/HarvsG/ha-glinet4-integration.git . (The . at the end is important)
  3. Reboot homeassistant
  4. Add the new Glinet integration under Devices and services
  5. Edit the host path with you router IP - ensure you keep the http://
  6. Add your router admin page login password (not your WIFI password). Placeholder is GL-inet's default goodlife, but this should be changed.

Dev set up

  1. Set up the vscode homeassistant core dev setup
  • Or you could just use a running install of homeassistant (restarts are required for a lot of changes)
  1. Run once to generate directories
  2. create a config/custom_components/glinet directory
  3. git clone https://github.com/HarvsG/ha-glinet4-integration.git .
  4. Note, the vscode git tracker will track the parent repo (ha core), but command line git will still work within the glinet dir
  5. You may need to config a new ssh key inside the container. Use this - this will be overwitten if you rebuild the container

TODO

  • Auto detect router IP for config flow - assume it is the default gateway, test an enpoint that doesn't require auth (/model or /hello), fallback to default 192.168.8.1
  • Add switches for wireguard and open vpn (client and server), done for wireguard client, but we can probably do all programatically rather than repeating boilerplate
    • worth considering you can have multiple clients, most of the API endpoints act on the last used client config. Can we get a list from the API and create switches for all? Maybe (router/vpn/status?)
  • Support HACS - lets get some more features working first
  • Allow deletion of unhelpful device tracker devices/entities, docs, example
  • Clean, comment and refactor code
  • Add tests - will need to mock the API
  • Allow reconfig for password changes - currently have to delete and re-add integration
  • Look into using https instead of http
  • Add features:
    • Upload/Download sensors
    • Internet reachable sensors (remember that API timesout when internet not reachable)
    • Public IP sensor
    • Diagnostic sensors for stats in (/router/status) such as uptime, LAN IP and memory useage
  • Consider features

Tested on

  • Beryl MT3000
  • Convexa B1300

Depends on

https://github.com/HarvsG/gli4py

ha-glinet4-integration's People

Contributors

harvsg avatar mikelcalvo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

mikelcalvo

ha-glinet4-integration's Issues

Wireguard VPN Issue

I am using a GLinet Flint Router with a WireGuard client running on it. However, the integration does not effectively control the VPN. Ideally, I should be able to toggle it on and off, but this functionality is not working as expected.

Interestingly, when I activate the VPN through the router, I can then deactivate it using Home Assistant. The Home Assistant switch briefly toggles off, but then shortly after shows that the VPN is still on, even though it should be off.

After this, I am unable to control the switch anymore. Only when I activate the VPN again through the router, I can once again deactivate it using Home Assistant.

Home Assistant

Core 2024.3.0
Supervisor 2024.03.0
Operating System 12.1
Frontend 20240306.0

Router

Hostname GL-AX1800
Model GL Technologies, Inc. AX1800
Architecture ARMv7 Processor rev 4 (v7l)
OpenWrt Version OpenWrt 21.02-SNAPSHOT r16399+165-c67509efd7
Kernel Version 4.4.60

Network Statuses

I have been looking at trying to integrate my gl inet for network statuses.

I have written a simple Powershell script that logs in, checks the network Statuses and returns an enum indicating if it is using wan(broadband) or tether(spare phone) for internet.

It has since occured to me that rather than having this script running, it could be a sensor or such like in home assistant. Which could expose the range of possible states.

Can I help in any way yo do this?

Thanks.

Problem with GL.iNet Flint (GL-AX1800) Integration Setup: Unexpected Error

I just wanted to set up the integration, but unfortunately I have the following error with my gl.inet Flint (GL-AX1800):

image
Logger: custom_components.glinet.config_flow
Source: custom_components/glinet/config_flow.py:128
Integration: glinet
First occurred: 08:27:03 (3 occurrences)
Last logged: 08:27:09

Unexpected exception
Traceback (most recent call last):
  File "/config/custom_components/glinet/config_flow.py", line 128, in async_step_user
    info = await validate_input(self.hass, user_input)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/glinet/config_flow.py", line 90, in validate_input
    if not await hub.connect():
           ^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/glinet/config_flow.py", line 49, in connect
    res = await self.router.router_model()
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/uplink/clients/io/asyncio_strategy.py", line 32, in execute
    return await executable.execute()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/uplink/clients/io/asyncio_strategy.py", line 21, in invoke
    response = await callback.on_success(response)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/uplink/clients/io/asyncio_strategy.py", line 19, in invoke
    response = await callback.on_failure(type(error), error, tb)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/uplink/clients/io/execution.py", line 108, in on_failure
    return self._io.fail(exc_type, exc_val, exc_tb)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/uplink/clients/io/interfaces.py", line 300, in fail
    compat.reraise(exc_type, exc_val, exc_tb)
  File "/usr/local/lib/python3.11/site-packages/six.py", line 719, in reraise
    raise value
  File "/usr/local/lib/python3.11/site-packages/uplink/clients/io/asyncio_strategy.py", line 16, in invoke
    response = await func(*args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/uplink/clients/aiohttp_.py", line 27, in new_callback
    response = callback(response)
               ^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/uplink/builder.py", line 47, in wrapper
    return func(self._consumer, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/uplink/hooks.py", line 21, in wrapper
    return hook(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/gli_py/error_handling.py", line 34, in raise_for_status
    raise UnsuccessfulRequest(response.url)
gli_py.error_handling.UnsuccessfulRequest: http://192.168.8.1/cgi-bin/api/router/model

Any idea how I can solve this?

Config flow could not be loaded: {"message":"Invalid handler specified"}

Unfortunately, seems like something got broken, I cannot add integration, this is what I get:
image

And here are system logs:

2023-12-15 12:32:23.786 ERROR (MainThread) [homeassistant.loader] Unexpected exception importing platform custom_components.glinet.config_flow
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/loader.py", line 834, in get_platform
    cache[full_name] = self._import_platform(platform_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/loader.py", line 851, in _import_platform
    return importlib.import_module(f"{self.pkg_path}.{platform_name}")
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "", line 1204, in _gcd_import
  File "", line 1176, in _find_and_load
  File "", line 1126, in _find_and_load_unlocked
  File "", line 241, in _call_with_frames_removed
  File "", line 1204, in _gcd_import
  File "", line 1176, in _find_and_load
  File "", line 1147, in _find_and_load_unlocked
  File "", line 690, in _load_unlocked
  File "", line 940, in exec_module
  File "", line 241, in _call_with_frames_removed
  File "/config/custom_components/glinet/__init__.py", line 9, in 
    from .router import GLinetRouter
  File "/config/custom_components/glinet/router.py", line 322
    if self._wireguard_clients[response["peer_id"]]
                                                   ^
SyntaxError: expected ':'

config flow unsuccessfull when trying to add GL-XE300 router

I tried to install your custom integration into my test environment and i'm getting an error when i try to configure the integration.
See messages from the log. I tried several times by deleting the integration and adding it again, installint the tailscale pulgins (that i don't use).
My router is a GL-XE300 (Puli) with the latest V4 firmware installed.
Home Assistant is also the latest version (2024.8.1)

2024-08-13T16:57:02.076430262Z �[33m2024-08-13 18:57:02.072 WARNING (MainThread) [custom_components.glinet.config_flow] Attempting to connect to router, success:True�[0m
2024-08-13T16:57:02.403075602Z Exception ignored in: <function AiohttpClient.__del__ at 0xffff75aa19e0>
2024-08-13T16:57:02.403178277Z Traceback (most recent call last):
2024-08-13T16:57:02.403199571Z   File "/usr/local/lib/python3.12/site-packages/uplink/clients/aiohttp_.py", line 75, in __del__
2024-08-13T16:57:02.404728609Z     asyncio.get_event_loop().run_until_complete(
2024-08-13T16:57:02.404830992Z   File "/usr/local/lib/python3.12/asyncio/base_events.py", line 663, in run_until_complete
2024-08-13T16:57:02.405272027Z     self._check_running()
2024-08-13T16:57:02.406579089Z   File "/usr/local/lib/python3.12/asyncio/base_events.py", line 622, in _check_running
2024-08-13T16:57:02.406667471Z     raise RuntimeError('This event loop is already running')
2024-08-13T16:57:02.406994455Z RuntimeError: This event loop is already running
2024-08-13T16:57:02.414075809Z �[33m2024-08-13 18:57:02.409 WARNING (Thread-51 (_target)) [py.warnings] /usr/local/lib/python3.12/asyncio/base_events.py:2008: RuntimeWarning: coroutine 'ClientSession.close' was never awaited
2024-08-13T16:57:02.414201527Z   def get_debug(self):
2024-08-13T16:57:02.414229238Z �[0m
2024-08-13T16:57:02.415056762Z �[31m2024-08-13 18:57:02.410 ERROR (Thread-51 (_target)) [homeassistant] Error doing job: Unclosed client session (None)�[0m
2024-08-13T16:57:02.415875827Z �[31m2024-08-13 18:57:02.411 ERROR (Thread-51 (_target)) [homeassistant] Error doing job: Unclosed connector (None)�[0m
2024-08-13T16:57:03.055270988Z �[31m2024-08-13 18:57:03.047 ERROR (MainThread) [homeassistant.config_entries] Error setting up entry GL-inet Xe300 for glinet
2024-08-13T16:57:03.055398457Z Traceback (most recent call last):
2024-08-13T16:57:03.055425876Z   File "/usr/src/homeassistant/homeassistant/config_entries.py", line 604, in async_setup
2024-08-13T16:57:03.055445710Z     result = await component.async_setup_entry(hass, self)
2024-08-13T16:57:03.055463795Z              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-08-13T16:57:03.055481297Z   File "/config/custom_components/glinet/__init__.py", line 53, in async_setup_entry
2024-08-13T16:57:03.055499090Z     await router.setup()
2024-08-13T16:57:03.055517466Z   File "/config/custom_components/glinet/router.py", line 154, in setup
2024-08-13T16:57:03.055534676Z     await self.update_all()
2024-08-13T16:57:03.055551886Z   File "/config/custom_components/glinet/router.py", line 207, in update_all
2024-08-13T16:57:03.055569095Z     await self.update_tailscale_state()
2024-08-13T16:57:03.055586597Z   File "/config/custom_components/glinet/router.py", line 330, in update_tailscale_state
2024-08-13T16:57:03.055604098Z     if not await self._api.tailscale_configured():
2024-08-13T16:57:03.055670603Z            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-08-13T16:57:03.055695397Z   File "/usr/local/lib/python3.12/site-packages/gli4py/glinet.py", line 238, in tailscale_configured
2024-08-13T16:57:03.055779404Z     if await self._tailscale_status() != []:
2024-08-13T16:57:03.055799530Z        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-08-13T16:57:03.055817615Z   File "/usr/local/lib/python3.12/site-packages/gli4py/glinet.py", line 229, in _tailscale_status
2024-08-13T16:57:03.055835700Z     return await self._request(self.gen_sid_payload('call', ['tailscale', 'get_status'], self.sid))
2024-08-13T16:57:03.055853201Z            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-08-13T16:57:03.055871286Z   File "/usr/local/lib/python3.12/site-packages/uplink/clients/io/asyncio_strategy.py", line 32, in execute
2024-08-13T16:57:03.055888787Z     return await executable.execute()
2024-08-13T16:57:03.055905997Z            ^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-08-13T16:57:03.055923790Z   File "/usr/local/lib/python3.12/site-packages/uplink/clients/io/asyncio_strategy.py", line 21, in invoke
2024-08-13T16:57:03.055941583Z     response = await callback.on_success(response)
2024-08-13T16:57:03.055958501Z                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-08-13T16:57:03.055976003Z   File "/usr/local/lib/python3.12/site-packages/uplink/clients/io/asyncio_strategy.py", line 19, in invoke
2024-08-13T16:57:03.055993796Z     response = await callback.on_failure(type(error), error, tb)
2024-08-13T16:57:03.056011005Z                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-08-13T16:57:03.056036091Z   File "/usr/local/lib/python3.12/site-packages/uplink/clients/io/execution.py", line 108, in on_failure
2024-08-13T16:57:03.056054759Z     return self._io.fail(exc_type, exc_val, exc_tb)
2024-08-13T16:57:03.056072844Z            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-08-13T16:57:03.056090637Z   File "/usr/local/lib/python3.12/site-packages/uplink/clients/io/interfaces.py", line 300, in fail
2024-08-13T16:57:03.056107846Z     compat.reraise(exc_type, exc_val, exc_tb)
2024-08-13T16:57:03.056125056Z   File "/usr/local/lib/python3.12/site-packages/six.py", line 719, in reraise
2024-08-13T16:57:03.056142849Z     raise value
2024-08-13T16:57:03.056167934Z   File "/usr/local/lib/python3.12/site-packages/uplink/clients/io/asyncio_strategy.py", line 16, in invoke
2024-08-13T16:57:03.056186311Z     response = await func(*args, **kwargs)
2024-08-13T16:57:03.056202937Z                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-08-13T16:57:03.056220439Z   File "/usr/local/lib/python3.12/site-packages/uplink/clients/aiohttp_.py", line 27, in new_callback
2024-08-13T16:57:03.056238232Z     response = callback(response)
2024-08-13T16:57:03.056255150Z                ^^^^^^^^^^^^^^^^^^
2024-08-13T16:57:03.056272651Z   File "/usr/local/lib/python3.12/site-packages/uplink/builder.py", line 47, in wrapper
2024-08-13T16:57:03.056290444Z     return func(self._consumer, *args, **kwargs)
2024-08-13T16:57:03.056354616Z            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-08-13T16:57:03.056373867Z   File "/usr/local/lib/python3.12/site-packages/uplink/hooks.py", line 21, in wrapper
2024-08-13T16:57:03.056391661Z     return hook(*args, **kwargs)
2024-08-13T16:57:03.056408870Z            ^^^^^^^^^^^^^^^^^^^^^
2024-08-13T16:57:03.056426080Z   File "/usr/local/lib/python3.12/site-packages/gli4py/error_handling.py", line 33, in raise_for_status
2024-08-13T16:57:03.056444165Z     raise NonZeroResponse("Request returned error code %s with message:' %s'. Full response %s" % (res['error']['code'], res['error']['message'],res))
2024-08-13T16:57:03.056462833Z gli4py.error_handling.NonZeroResponse: Request returned error code -32601 with message:' Method not found'. Full response {'id': 0, 'jsonrpc': '2.0', 'error': {'message': 'Method not found', 'code': -32601}}�[0m

No attribute 'get'

dev_info = wrt_devices.get(device_mac)

Log Details (ERROR)
This error originated from a custom integration.
Logger: homeassistant
Source: custom_components/glinet/router.py:280
Integration: GL-inet
First occurred: July 25, 2023 at 1:02:20 AM (7783 occurrences)
Last logged: 5:53:20 PM

Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "/config/custom_components/glinet/router.py", line 200, in update_all
    await self.update_device_trackers()
  File "/config/custom_components/glinet/router.py", line 280, in update_device_trackers
    dev_info = wrt_devices.get(device_mac)
               ^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'get'

Cannot Setup Router GL-inet Ax1800

After connecting to my router I get a sucess message ( Created configuration for GL-inet Ax1800. ).
However the integration instantly states "Failed to set up". Firmware is v4.1.0



2023-09-24 00:43:48.635 ERROR (MainThread) [custom_components.glinet.router] Response from http://192.168.86.1 to request wireguard_client_list is of type <class 'list'>, Response: []
2023-09-24 00:43:48.662 ERROR (MainThread) [homeassistant.config_entries] Error setting up entry GL-inet Ax1800 for glinet
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/config_entries.py", line 387, in async_setup
result = await component.async_setup_entry(hass, self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/config/custom_components/glinet/__init__.py", line 53, in async_setup_entry
await router.setup()
File "/config/custom_components/glinet/router.py", line 148, in setup
await self.update_all()
File "/config/custom_components/glinet/router.py", line 200, in update_all
await self.update_wireguard_client_state()
File "/config/custom_components/glinet/router.py", line 322, in update_wireguard_client_state
self._wireguard_clients[response["peer_id"]].connected = (response["status"] == 1)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^
KeyError: 0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.