WattBox Integration

I’m a wattbox user and would be happy to help test. I’ve got 2 house w/ WB’s installed. House 1 has older gear, house 2 has brand new WB gear.

Here’s how I see them in HA:
‘’’
wattbox:

  • host: xx.xx.x.xx
    name: WB-700-IPV-12
    username: XXXXX
    password: XXXXXX
    scan_interval: 00:00:30
  • host: xx.xx.x.xx
    name: WB-300-IP-3 Network Control
    username: XXXXX
    password: XXXXX
    scan_interval: 00:00:30
    ‘’’

This config.yaml entry brings both WB’s into HA and creates switches for each outlet and sensors for all the other things available from the WB.

How can I help? :slight_smile:

There’s not much more for you to do since you get all the sensors and switches in HA. My issue is that I have an 800 series which has a new interface and new protocol.

I have 7 or 8 of the new 800 series WBs, just offering g a test bed of yall need.

More testers are always welcome. Now if we could locate a few coders.

1 Like

I have 3 800 series as well and nothing shows up when you try to add them, no failures in the logs but no entities made either.

I know its been a long while but I was making a few tweaks and got reminded of this thread. I did a bunch more digging yesterday and still could not find any docs about the new web UI / API. I ended up sending them an email and they said they don’t have docs for the new UI. Mostly because they want you to use OvrC.

I would definitely prefer to work with an HTTP API vs telnet, but in theory telnet could work to control all the models. Unfortunately no matter what I do I cannot get my 700 to listen for telnet connections. So I cannot even try and dev against it. I fought with it for a few hours last night and didn’t get anywhere. I might try and call their support number next week, but no idea if it will do anything.

I would be willing to take a crack at something for the other models but to do that I would have to see what the new web UI is doing to figure out how it works. Without having one myself, I would need to get access to one to tinker with it. @flippedcracker @Debo @jes1417 Anyone willing to help facilitate something?

No guarantees any work will result in something useful, but would be interesting to try. Most of these ideas would require lots of back and forth with incremental improvements. It took me a few evenings of tinkering to get the initial version working with direct access, so not sure how long it might take remotely.

I am pretty flexible, can do whatever you might be comfortable with. Some potential ideas:

  • Lend me one to develop against. Doubt anyone will be willing to but it would be the easiest way to figure it out. Hands on locally I will know if I can get it working pretty quick and would get it back to you without delay.
  • A VPN connection and the creds to connect to one. I don’t really like asking for this either, but it would let me tinker with it on my time and be almost as good as having it locally. WireGuard Add-On?
  • Some sort of remote desktop connection, where you can log into the UI for me and then can keep an eye on what I am doing while I poke around.
  • Screen share. You drive while I tell you what to do. Lots of time clicking around using the dev tools in the web browser.
  • Wireshark. Set it to capture traffic for just traffic to and from your wattbox’s IP then browse to it via http, log in and start performing actions in the UI. Note, no https, as it will all be encrypted and not usable. I need to be able to read all the traffic.

The new 800 series uses SSH instead of HTTP, I don’t have a spare to send off currently but I think I can give you VPN creds to access mine.

Here is the API for telnet and SSH.

They do also have a local web UI which means they seem to have some sort of web API as well. They just didn’t want to give out docs for it. I thought the earlier models had a Telnet API as well, the difference being adding SSH for encryption. Then again my 700 refuses to enable Telnet, so maybe not?

I’d like to at least poke the UI if possible. Web API would be highly preferable just because of my familiarity with them. But if I absolutely necessary could probably build something close out from the v2.4 docs. I guess at least SSH has better Python async support than Telnet.

My email is on my GitHub, or can find me through Discord whatever works.

I’ve emailed you

I installed this integration for my new WB-800VPS-IPVM-12. The various binary sensors seem to be reading ok as well as the master switch. However, the voltage, watt, and current sensors show 0. I don’t see anything in the logs. Any pointers on this? The values are present when I log directly into Wattbox. Thanks!

We’re waiting for some kind developer to add 800-series support.:crossed_fingers:t2:

2 Likes

I did get access to one to test, and started the play with it. Unfortunately they are completely different and the main API is only over SSH / Telnet. So its basically starting from scratch again, but a little worse because I am trying to match it up as best as possible with what already exists for the older ones.

I did get things framed out in a way that I think will work. I just haven’t had time to work on it in like two months. Don’t really have any sort of ETA, but did want to at least add an update here to say there has been some progress.

2 Likes

My WB-700 died so now have a WB-800VPS-IPVM-18. Would love support for this in HA so I can track per-port usage in InfluxDB/Grafana… I dont have much more to offer then a big thank you to anyone able to work on this!

Well - I saw someone else offer but if needed I could dedicate some time over VPN to someone developing, I could give you a sandbox with the WB-800 with some dummy loads and a camera looking at it if thats helpful. I’d just have to rewire my rack temporarily to set this up.

@eseglem is your code available somewhere?

Does this help at all? (I am not a python programmer)

Output is:

Opening Telnet connection
This device has 18 outlets
Results of command…
[[1.0, 0.0, 0.0, 114.44],
[2.0, 45.36, 0.33, 114.44],
[3.0, 27.77, 0.17, 114.44],
[4.0, 7.78, 0.01, 114.44],
[5.0, 5.91, 0.0, 114.44],
[6.0, 115.45, 0.92, 114.44],
[7.0, 110.17, 0.88, 114.44],
[8.0, 100.91, 0.8, 114.44],
[9.0, 3.43, 0.0, 114.44],
[10.0, 17.62, 0.13, 114.44],
[11.0, 0.0, 0.0, 114.44],
[12.0, 0.0, 0.0, 114.44],
[13.0, 5.33, 0.0, 114.44],
[14.0, 8.01, 0.01, 114.44],
[15.0, 0.07, 0.0, 114.44],
[16.0, 0.12, 0.0, 114.44],
[17.0, 0.0, 0.0, 114.44],
[18.0, 0.0, 0.0, 114.44]]
DONE Results of command…

Code is

# quick python script to get data 
# from a wattbox 800 via telnet
# output is
# [OutletNumber, Watts, Amps, Voltage]
#
from telnetlib import Telnet
from pprint import pprint

hostname = "wb-800"
port = 23
username = "wattbox"
password = "wattbox"
debug_level = 0

devices_result = []

print("Opening Telnet connection")
with Telnet(hostname, port) as tn:
    try:
        tn.set_debuglevel(debug_level)
        tn.msg("Created new Telnet instance")
        tn.read_until(b'Username : ', 2)
        tn.msg("Found username")
        tn.write((username + '\n').encode('ascii'))
        tn.msg("Sending username")
        tn.read_until(b'Password : ', 2)
        tn.msg("Found password")
        tn.write((password + '\n').encode('ascii'))
        tn.msg("Sending password")
        
        tn.read_until(b'Successfully Logged In!', 2)
        tn.msg("Found prompt")
        
        # Get number of outlets
        tn.write(('?OutletCount\n').encode('ascii'))
        # throw away everything up to =
        tn.read_until(b'=', 2)
        # this is the result of the command
        number_of_outlets = int(tn.read_until(b'\n').strip().decode())
        print(f"This device has {number_of_outlets} outlets")

        for i in range(1,number_of_outlets+1):
            tn.write((f'?OutletPowerStatus={i}\n').encode('ascii'))
            tn.msg(f"Getting Outlet {i} Power Status")
            
            # throw away everything up to =
            tn.read_until(b'=', 2)
            # this is the result of the command
            single_string = tn.read_until(b'\n').strip().split(b',')
            devices_result.append([float(x.decode()) for x in single_string])
            tn.msg("Command complete")

        tn.close()
        tn.msg("Closed connection")
        exit
    except EOFError:
        print("Unexpected response from router")
        #return
    except ConnectionRefusedError:
        print("Connection refused by router. Telnet enabled?")
        #return
    except Exception as e: 
        print("------FATAL ERROR------")
        print(e)

print("Results of command...")
pprint(devices_result)
print("DONE Results of command...")

It wasn’t really in the greatest spot to share, so I just got things to an alpha ish state.

Oh, and it overhauled to use actual async under the hood on the http side for older ones as well.

Readme isn’t updated but the develop branch may now work for newer devices. You’ll probably need to manually install it for now . GitHub - eseglem/hass-wattbox at develop

Config hasn’t changed at all yet, just stick in port 22 for ssh or 23 for telnet.

The async http part is tested a tiny amount right now. The stuff for the newer ones is completely untested and comes with no guarantees. Use at your own risk. I did enough testing a while back I think it will be close to a working version, but didn’t attempt to connect to one with it yet.

If anyone does manage to get it working, definitely let me know how it goes.

The meat of the code for actually connecting and managing all that stuff is in GitHub - eseglem/pywattbox at develop I basically split the old code into a BaseWattbox and HttpWattbox then made an IpWattbox which has all the same functions on it, so they can be called the same way, and is transparent to HA. They behave pretty differently from eachother, so its not the nicest to make work but should work reasonable enough.

2 Likes

I get these errors when trying to add the 800 series with the dev branch

This error originated from a custom integration.

Logger: homeassistant.setup
Source: custom_components/wattbox/__init__.py:105
Integration: WattBox (documentation, issues)
First occurred: 7:51:23 PM (1 occurrences)
Last logged: 7:51:23 PM

Error during setup of component wattbox
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/asyncio/selector_events.py", line 862, in _read_ready__data_received
    data = self._sock.recv(self.max_size)
ConnectionResetError: [Errno 104] Connection reset by peer

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/httpcore/_exceptions.py", line 10, in map_exceptions
    yield
  File "/usr/local/lib/python3.10/site-packages/httpcore/backends/asyncio.py", line 34, in read
    return await self._stream.receive(max_bytes=max_bytes)
  File "/usr/local/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 1274, in receive
    raise self._protocol.exception
anyio.BrokenResourceError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/httpx/_transports/default.py", line 60, in map_httpcore_exceptions
    yield
  File "/usr/local/lib/python3.10/site-packages/httpx/_transports/default.py", line 353, in handle_async_request
    resp = await self._pool.handle_async_request(req)
  File "/usr/local/lib/python3.10/site-packages/httpcore/_async/connection_pool.py", line 253, in handle_async_request
    raise exc
  File "/usr/local/lib/python3.10/site-packages/httpcore/_async/connection_pool.py", line 237, in handle_async_request
    response = await connection.handle_async_request(request)
  File "/usr/local/lib/python3.10/site-packages/httpcore/_async/connection.py", line 90, in handle_async_request
    return await self._connection.handle_async_request(request)
  File "/usr/local/lib/python3.10/site-packages/httpcore/_async/http11.py", line 112, in handle_async_request
    raise exc
  File "/usr/local/lib/python3.10/site-packages/httpcore/_async/http11.py", line 91, in handle_async_request
    ) = await self._receive_response_headers(**kwargs)
  File "/usr/local/lib/python3.10/site-packages/httpcore/_async/http11.py", line 155, in _receive_response_headers
    event = await self._receive_event(timeout=timeout)
  File "/usr/local/lib/python3.10/site-packages/httpcore/_async/http11.py", line 191, in _receive_event
    data = await self._network_stream.read(
  File "/usr/local/lib/python3.10/site-packages/httpcore/backends/asyncio.py", line 31, in read
    with map_exceptions(exc_map):
  File "/usr/local/lib/python3.10/contextlib.py", line 153, in __exit__
    self.gen.throw(typ, value, traceback)
  File "/usr/local/lib/python3.10/site-packages/httpcore/_exceptions.py", line 14, in map_exceptions
    raise to_exc(exc)
httpcore.ReadError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/setup.py", line 256, in _async_setup_component
    result = await task
  File "/config/custom_components/wattbox/__init__.py", line 105, in async_setup
    hass.data[DOMAIN_DATA][name] = await async_create_http_wattbox(
  File "/usr/local/lib/python3.10/site-packages/pywattbox/http_wattbox.py", line 239, in async_create_http_wattbox
    return await _async_create_wattbox(
  File "/usr/local/lib/python3.10/site-packages/pywattbox/base.py", line 115, in _async_create_wattbox
    await wattbox.async_get_initial()
  File "/usr/local/lib/python3.10/site-packages/pywattbox/http_wattbox.py", line 38, in async_get_initial
    response = await client.get(
  File "/usr/local/lib/python3.10/site-packages/httpx/_client.py", line 1757, in get
    return await self.request(
  File "/usr/local/lib/python3.10/site-packages/httpx/_client.py", line 1533, in request
    return await self.send(request, auth=auth, follow_redirects=follow_redirects)
  File "/usr/local/lib/python3.10/site-packages/httpx/_client.py", line 1620, in send
    response = await self._send_handling_auth(
  File "/usr/local/lib/python3.10/site-packages/httpx/_client.py", line 1648, in _send_handling_auth
    response = await self._send_handling_redirects(
  File "/usr/local/lib/python3.10/site-packages/httpx/_client.py", line 1685, in _send_handling_redirects
    response = await self._send_single_request(request)
  File "/usr/local/lib/python3.10/site-packages/httpx/_client.py", line 1722, in _send_single_request
    response = await transport.handle_async_request(request)
  File "/usr/local/lib/python3.10/site-packages/httpx/_transports/default.py", line 352, in handle_async_request
    with map_httpcore_exceptions():
  File "/usr/local/lib/python3.10/contextlib.py", line 153, in __exit__
    self.gen.throw(typ, value, traceback)
  File "/usr/local/lib/python3.10/site-packages/httpx/_transports/default.py", line 77, in map_httpcore_exceptions
    raise mapped_exc(message) from exc
httpx.ReadError
Logger: homeassistant.setup
Source: setup.py:363
First occurred: 7:51:23 PM (3 occurrences)
Last logged: 7:51:23 PM

Unable to prepare setup for platform wattbox.binary_sensor: Unable to set up component.
Unable to prepare setup for platform wattbox.sensor: Unable to set up component.
Unable to prepare setup for platform wattbox.switch: Unable to set up component.

I think I posted kinda late at night and should have had some more info. Looks like its trying to do httpx, so its defaulting to port 80 probably, will need to pick the port as 22 (ssh) or 23 (telnet).

wattbox:
- host: 192.168.1.100
  port: 22
  name: wattbox1
  username: username1
  password: password1

I kind of rushed it out it still needs testing. I am sure something won’t quite work right but I think it should be pretty close.

chances to add long term statistics so we can add wattbox to the energy dashboard? @eseglem

I tried with both ports 22 and 23

I tried with port 22 and it was throwing an error:
Optional transport plugin ‘ssh2’ is not installed!
/
ModuleNotFoundError: No module named ‘ssh2’

I should have grabbed the full stack trace for you but I got it working by using telnet for now.

EDIT:

Initially it connected successfully, then I tried to change the state of an outlet from within Home Assistant and it threw the following error:

Source: custom_components/wattbox/switch.py:96
Integration: Home Assistant WebSocket API (documentation, issues)
First occurred: 12:15:52 PM (1 occurrences)
Last logged: 12:15:52 PM

[139673919540960] timed out during in channel telnet authentication
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/scrapli/channel/async_channel.py", line 367, in channel_authenticate_telnet
    buf = await asyncio.wait_for(self.read(), timeout=read_interval)
  File "/usr/local/lib/python3.10/asyncio/tasks.py", line 432, in wait_for
    await waiter
asyncio.exceptions.CancelledError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.10/asyncio/tasks.py", line 456, in wait_for
    return fut.result()
asyncio.exceptions.CancelledError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/scrapli/decorators.py", line 191, in decorate
    return await asyncio.wait_for(wrapped_func(*args, **kwargs), timeout=timeout)
  File "/usr/local/lib/python3.10/asyncio/tasks.py", line 458, in wait_for
    raise exceptions.TimeoutError() from exc
asyncio.exceptions.TimeoutError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 199, in handle_call_service
    await hass.services.async_call(
  File "/usr/src/homeassistant/homeassistant/core.py", line 1820, in async_call
    task.result()
  File "/usr/src/homeassistant/homeassistant/core.py", line 1857, in _execute_service
    await cast(Callable[[ServiceCall], Awaitable[None]], handler.job.target)(
  File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 216, in handle_service
    await service.entity_service_call(
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 798, in entity_service_call
    future.result()  # pop exception if have
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 977, in async_request_call
    await coro
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 838, in _handle_entity_call
    await result
  File "/config/custom_components/wattbox/switch.py", line 96, in async_turn_off
    await self.hass.data[DOMAIN_DATA][self.wattbox_name].outlets[
  File "/usr/local/lib/python3.10/site-packages/pywattbox/base.py", line 137, in async_turn_off
    await self.wattbox.async_send_command(self.index, Commands.OFF)
  File "/usr/local/lib/python3.10/site-packages/pywattbox/ip_wattbox.py", line 246, in async_send_command
    async with self.async_driver as conn:
  File "/usr/local/lib/python3.10/site-packages/scrapli/driver/base/async_driver.py", line 42, in __aenter__
    await self.open()
  File "/usr/local/lib/python3.10/site-packages/scrapli/driver/base/async_driver.py", line 95, in open
    await self.channel.channel_authenticate_telnet(
  File "/usr/local/lib/python3.10/site-packages/scrapli/decorators.py", line 193, in decorate
    _handle_timeout(
  File "/usr/local/lib/python3.10/site-packages/scrapli/decorators.py", line 134, in _handle_timeout
    raise ScrapliTimeout(message)
scrapli.exceptions.ScrapliTimeout: timed out during in channel telnet authentication

Now it does not want to connect.