Git Product home page Git Product logo

aio-powerview-api's Introduction

Code style: black PyPI codecov example workflow

Aio PowerView API

A python async API for PowerView blinds written for Home-Assistant.

Have a look at the examples folder for some guidance how to use it.

Capabilities

Description Capabilities Primary Secondary Tilt Tilt Position Vertical DualShade
Bottom Up 0 X
Bottom Up Tilt 180° 1* X 180° Closed
Bottom Up Tilt 90° 1 X 90° Closed
Bottom Up Tilt 180° 2 X 180° Anywhere
Vertical 3 X X
Vertical Tilt Anywhere 4 X 180° Anywhere X
Tilt Only 180° 5 180° Anywhere
Top Down 6 X
Top Down Bottom Up 7 X X
Dual Shade Overlapped 8 X X X
Dual Shade Overlapped Tilt 90° 9 X X 90° Closed X
Dual Shade Overlapped Tilt 90° 10 X X 180° Closed X
Dual Shade Overlapped Illuminated 11^ X X X

^ Capability 11 shades have the same functionality as capability 8 shades, plus an inbuild light. Light management not available via aiopvapi at this time

Shades

Shades that have been directly added to the API are listed below and should function correctly. In most cases this is identification is purely aestetic.

Shades not listed will get their features from their capabilities, unfortunately the json returned from the shade can sometimes be incorrect and we need to override the features for the API (and Home-Assistant) to read them correctly.

Name Type Capability
AC Roller 49 0
Aura Illuminated, Roller 49 11
Banded Shades 52 0
Bottom Up 5 0
Curtain, Left Stack 69 3
Curtain, Right Stack 70 3
Curtain, Split Stack 71 3
Designer Roller 1 0
Duette 6 0
Duette, Top Down Bottom Up 8 7
Duette Architella, Top Down Bottom Up 33 7
Duette DuoLite, Top Down Bottom Up 9 7
Duolite Lift 79 9
Facette 43 1
M25T Roller Blind 42 0
Palm Beach Shutters 66 5
Pirouette 18 1
Pleated, Top Down Bottom Up 47 7
Provenance Woven Wood 19 0
Roman 4 0
Silhouette 23 1
Silhouette Duolite 38 9
Sonnette 53 0
Skyline Panel, Left Stack 26 3
Skyline Panel, Right Stack 27 3
Skyline Panel, Split Stack 28 3
Top Down 7 6
Twist 44 1*
Vignette 31 0
Vignette 32 0
Vignette 84 0
Vignette Duolite 65 8
Vertical 3 0
Vertical Slats, Left Stack 54 4
Vertical Slats, Right Stack 55 4
Vertical Slats, Split Stack 56 4
Venetian, Tilt Anywhere 51 2
Venetian, Tilt Anywhere 62 2

* No other shade are known to have this capability and currently the only way to get this functionality is by hardcoding into this API

Development

  • Install dev requirements.
  • Testing is done using NOX
  • Build a package: python .\setup.py bdist bdist_wheel --universal
  • upload a package twine upload dist/*.*

Changelog

1.6.15

  • Constrain aiohttp package versions.

v1.6.19

  • Add endpoints and handle 423 response
  • Remove loop as argument

v2.0.0

  • Add support for all known shade types
  • Fallback to shade recognition based on capability
  • Clamping to prevent MIN_POSITION or MAX_POSITION being exceeded
  • Code refactoring

v2.0.1

  • Invert type 3 & 4 to match api documentation from hunter douglas
  • Add type 10

v2.0.2

  • Bug Fix to handle shades with unexpected json responses

v2.0.3

  • Add Type 26, 27 & 28 - Skyline Panels
  • Force capability 1 for Type 44 - Twist
  • Align class name standard

v2.0.4

  • Add Type 10 - SkyLift
  • Handle calls to update shade position during maintenance
  • Raise error directly on hub calls instead of logger

v3.0.0

  • Major overhaul to incorporate gateway version 3 API. Version can be automatically detected or manually specified.
  • UserData class is deprecated and replaced with Hub.
  • ShadePosition class now replaces the raw json management of shades in support of cross generational management.
  • Schedules / Automations are now supported by the API
  • New get_objecttype methods available to returned structured data objects for consistent management

v3.0.1

  • Raw hub data updates made via defined function (request_raw_data, request_home_data, request_raw_firware, detect_api_version)
  • Parse Gen 3 hub name based on serial + mac
  • Find API version based on firmware revision
  • Remove async_timeout and move to asyncio

v3.0.2

  • Add type 19 (Provenance Woven Wood)
  • Fix Positioning for ShadeVerticalTiltAnywhere + ShadeTiltOnly (Mid only)
  • Fix logging regression on initial setup
  • Fixes for ShadeVerticalTiltAnywhere + ShadeTiltOnly
  • Fix tests
  • Remove unneeded declerations
  • Fix shade position reporting for v2 shades
  • Dandle empty hub data being returned

v3.1.0

  • General docstring updates
  • Handle kwargs in websessions for management of timeout internally
  • Update error handling in tools
  • Handle empty values and zeros better
  • Add type 53 (Sonnette) and yype 95 (Aura Illuminated, Roller). Note: Type 95 do not support light control
  • Handle PowerType 11 + 12. Both are fixed and cannot be edited

v3.1.1

  • Fix missed timeout blocks and handle in websession

Links


aio-powerview-api's People

Contributors

alindner19 avatar bdraco avatar etsinko avatar fabaff avatar kingy444 avatar robert-alfaro avatar sander76 avatar

Stargazers

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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

aio-powerview-api's Issues

TopDown/BottomUp shades do not show two different enities anymore

All my TDBU shades stopped working correctly regarding the two different entities that will be created for each blind: Top and Bottom, after I installed these updates: HA Core 2022.9.4, HA Supervisor 2022.8.6, HA OS 9, running in an Intel macOS VirtualBox. I do have two PV hubs (I have 15 blinds of which 6 are TD/BU) configured as primary and secondary and the max. number of scenes (31) in the PowerView app.

My TDBU shades now each have only one entity for the cover, before it had two with suffixes _bottom and _top. A reload of the PowerView integration does not help. Restarting HA and PV does not help, removing the integration, restarting and adding it back again does not help.

After help from and debugging by Kingy444 it shows that for some reason my shades are matching on capabilities but aren’t reporting the correct capabilities (should be 7).

bottom up top down support

Hello!

I am hoping to convince someone to add support for bottom up top down (BUTD) support for this plugin. (a number of users have requested this over the years/months)

I am able to manipulate the BUTD shade by simply adjusting the position, for example this sets the shade to cover the bottom 50% of a window:

{
    "shade": {
        "positions": {
            "posKind1": 1,
            "posKind2": 2,
            "position1": 0,
            "position2": 32000
        }
    }
}

whereas if i invert those numbers, the top 50% of a window is covered:

    "shade": {
        "positions": {
            "posKind1": 1,
            "posKind2": 2,
            "position1": 0,
            "position2": 32000
        }
    }
}

it seems like right now the plugin simply adjusts the position2 variable. if we were able to change the current position slider for simply two text fields with BUTD blinds, allowing the user to input the top and bottom rail position — we'd have support.

I'm curious if anyone would be interested in doing this work? I am very happy to pay and hourly rate and provide QA, obviously.

PowerView API // Shade capabilities table

I am a code contributor for the openHAB binding for Hunter Douglas PowerView shades (see info below).

Just as you guys have, we are also facing the issue of how to fine tune the binding functionality and UI to match the physical capabilities of the different types of Hunter Douglas shades. As a result of extensive Googling of shade JSON payloads, and developer repositories on GitHub (including yours), I was able to build the following (tentative) table of shade type attributes versus capabilities attributes. And I am pleased to (hereby) share it with you.

=> Any further inputs or corrections would be very much appreciated - especially from @sander76 and (perhaps) @kingy444

image

Tilt broken for shutters

I have Palm Beach shutters and the tilt control does not work, throws exception (viewed from HA):

2024-01-24 17:07:57.188 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection] [127641256996928] ShadeTiltOnly.move() takes 1 positional argument but 2 were given
Traceback (most recent call last):
  File "/workspaces/home-assistant/homeassistant/components/websocket_api/commands.py", line 238, in handle_call_service
    response = await hass.services.async_call(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/home-assistant/homeassistant/core.py", line 2230, in async_call
    response_data = await coro
                    ^^^^^^^^^^
  File "/workspaces/home-assistant/homeassistant/core.py", line 2267, in _execute_service
    return await target(service_call)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/home-assistant/homeassistant/helpers/service.py", line 882, in entity_service_call
    single_response = await _handle_entity_call(
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/home-assistant/homeassistant/helpers/service.py", line 952, in _handle_entity_call
    result = await task
             ^^^^^^^^^^
  File "/workspaces/home-assistant/homeassistant/components/hunterdouglas_powerview/cover.py", line 415, in async_set_cover_tilt_position
    await self._async_set_cover_tilt_position(kwargs[ATTR_TILT_POSITION])
  File "/workspaces/home-assistant/homeassistant/components/hunterdouglas_powerview/cover.py", line 425, in _async_set_cover_tilt_position
    await self._async_execute_move(self._get_shade_tilt(target_hass_tilt_position))
  File "/workspaces/home-assistant/homeassistant/components/hunterdouglas_powerview/cover.py", line 233, in _async_execute_move
    response = await self._shade.move(move.request)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: ShadeTiltOnly.move() takes 1 positional argument but 2 were given

Discovered that the move() method is not actually implemented. I commented out the override just to see what happens.
Turns out the shutters tilt functions correctly without the override in place, however state reporting and such appears broken.

class ShadeTiltOnly(BaseShadeTilt):
    """Type 5 - Tilt Only 180°

    A shade with tilt anywhere capabilities only.
    """

    shade_types = (
        shade_type(66, "Palm Beach Shutters"),
    )

    capability = capability(
        5,
        ShadeCapabilities(
            tiltAnywhere=True,
            tilt180=True,
        ),
        "Tilt Only 180°",
    )

    open_position = {}
    close_position = {}

    open_position_tilt = {ATTR_POSITION1: MID_POSITION, ATTR_POSKIND1: 3}
    close_position_tilt = {ATTR_POSITION1: MIN_POSITION, ATTR_POSKIND1: 3}

    allowed_positions = (
        {ATTR_POSITION: {ATTR_POSKIND1: 3}, ATTR_COMMAND: ATTR_TILT},
    )

    # async def move(self):
    #     _LOGGER.error("Move not supported.")
    #     return

What can I do to provide more information or help out? I do recall manually trying "the other" python lib for powerview and it works for controlling tilt fine (it's been done before in python) but clearly bailed on it as this one is used in the HA integration.

Thank you for all your great work!

Test failure

With aiohttpp-3.8.0 one test seems to fail.

============================= test session starts ==============================
platform linux -- Python 3.9.6, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: /build/aiopvapi-1.6.14
============================= test session starts ==============================
platform linux -- Python 3.9.6, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: /build/source
collected 53 items                                                             

collected 22 items                                                             

tests/test_environ.py F........                                          [ 40%]
tests/test_errors.py .                                                   [ 45%]
tests/test_inbuf_overflow.py ..                                          [ 54%]
tests/test_max_request_body_size.py ..                                   [ 63%]
tests/test_start_response.py ...                                         [ 77%]
tests/test_static.py ....                                                [ 95%]
tests/test_wsgi.py .                                                     [100%]

=================================== FAILURES ===================================
___________________________ EnvironTest.testEnviron ____________________________

self = <tests.test_environ.EnvironTest testMethod=testEnviron>

    def testEnviron(self) -> None:
        with self.run_server(assert_environ) as client:
>           client.assert_response(headers={
                "Foo": "bar",
            })

tests/test_environ.py:99: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests/base.py:43: in assert_response
    self._test_case.assertEqual(response.status, 200)
E   AssertionError: 500 != 200
------------------------------ Captured log call -------------------------------
ERROR    aiohttp.server:web_protocol.py:400 Error handling request
Traceback (most recent call last):
  File "/nix/store/my82x39dchn0jp810nliflnrf6bvld4b-python3.9-aiohttp-3.8.0/lib/python3.9/site-packages/aiohttp/web_protocol.py", line 430, in _handle_request
    resp = await request_handler(request)
  File "/nix/store/my82x39dchn0jp810nliflnrf6bvld4b-python3.9-aiohttp-3.8.0/lib/python3.9/site-packages/aiohttp/web_app.py", line 504, in _handle
    resp = await handler(request)
  File "/build/source/aiohttp_wsgi/wsgi.py", line 294, in handle_request
    return await self._loop.run_in_executor(
  File "/nix/store/5bh6rpya1ar6l49vrhx1rg58dsa42906-python3-3.9.6/lib/python3.9/concurrent/futures/thread.py", line 52, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/build/source/aiohttp_wsgi/wsgi.py", line 147, in _run_application
    body_iterable = application(environ, start_response)
  File "/build/source/tests/test_environ.py", line 13, in do_environ_application
    func(environ)
  File "/build/source/tests/test_environ.py", line 23, in assert_environ
    assert environ["CONTENT_TYPE"] == ""
AssertionError: assert 'application/octet-stream' == ''
  + application/octet-stream
=========================== short test summary info ============================
FAILED tests/test_environ.py::EnvironTest::testEnviron - AssertionError: 500 ...
========================= 1 failed, 21 passed in 0.36s =========================

Timeout issues

Hoping to get your insight on the below - Home Assistant is throwing these errors for me.

Trying to get to the bottom of it (doing dev work on the integration for tdbu shades) but it looks like it stems from the aio request side rather than HomeAssistant.

I havent looked into your code too heavily yet but could maybe be related to the 423 response code we added a whileback and this call ? check_response(response, [200, 204])

Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/aiopvapi/helpers/aiorequest.py", line 66, in get
    response = await self.websession.get(url, params=params)
  File "/usr/local/lib/python3.9/site-packages/aiohttp/client.py", line 559, in _request
    await resp.start(conn)
  File "/usr/local/lib/python3.9/site-packages/aiohttp/client_reqrep.py", line 898, in start
    message, payload = await protocol.read()  # type: ignore[union-attr]
  File "/usr/local/lib/python3.9/site-packages/aiohttp/streams.py", line 616, in read
    await self._waiter
asyncio.exceptions.CancelledError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/aiopvapi/helpers/aiorequest.py", line 67, in get
    return await check_response(response, [200, 204])
  File "/usr/local/lib/python3.9/site-packages/async_timeout/__init__.py", line 116, in __exit__
    self._do_exit(exc_type)
  File "/usr/local/lib/python3.9/site-packages/async_timeout/__init__.py", line 212, in _do_exit
    raise asyncio.TimeoutError
asyncio.exceptions.TimeoutError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/config/custom_components/hunterdouglas_powerview_custom/cover.py", line 318, in _async_complete_schedule_update
    await self._async_force_refresh_state()
  File "/config/custom_components/hunterdouglas_powerview_custom/cover.py", line 322, in _async_force_refresh_state
    await self._shade.refresh()
  File "/usr/local/lib/python3.9/site-packages/aiopvapi/resources/shade.py", line 133, in refresh
    raw_data = await self.request.get(self._resource_path, {"refresh": "true"})
  File "/usr/local/lib/python3.9/site-packages/aiopvapi/helpers/aiorequest.py", line 70, in get
    raise PvApiConnectionError
aiopvapi.helpers.aiorequest.PvApiConnectionError

Hub v3 support?

Is there any chance of this being updated to support the newer API that Hub v3 uses or should I start looking to implement that on my own? I know it would probably be a rather large update which is why I ask.

Duolite support

Hello. I have the Hunter Douglas Duolite shades, which don't quite work with aiopvapi because the way the positions of the two shades are reported is a bit different from other shades. The Duolites have both a front (sheer) shade and a back (blackout) shade. They're not completely independent: the front shade has to be down all the way for the back shade to come down, and likewise the back shade has to be all the way up for the front shade to go up.

Here's an example of the shade object:

{
  "shade": {
    "id": 61912,
    "type": 79,
    "capabilities": -1,
    "batteryKind": 2,
    "smartPowerSupply": {
      "status": 0,
      "id": 0,
      "port": 0
    },
    "batteryStatus": 3,
    "batteryStrength": 180,
    "roomId": 23323,
    "firmware": {
      "revision": 2,
      "subRevision": 0,
      "build": 2996,
      "index": 88
    },
    "name": "TnVyc2VyeSBGcm9udA==",
    "groupId": 44249,
    "positions": {
      "position1": 65535,
      "posKind1": 1
    }
  }
}

It only reports a single position, but that position is either posKind1:1 or posKind1:2 depending on whether the position is for the front shade or the back shade. For example:

Back shade up, front shade half way: {"posKind1":1,"position1":32767}.

Back shade half down, front shade down: {"posKind1":2,"position1":32767}.

Back shade up, front shade down: either {"posKind1":1,"position1":0} or {"posKind1":2,"position1":65535} depending on which shade moved last.

If, for example, the back shade it up and the front shade is half way down and you set the position to {"posKind1":2,"position1":32767}, it will first lower the front shade all the way and then lower the back shade half way.

I'm guessing this needs a special shade type 79 in https://github.com/sander76/aio-powerview-api/blob/master/aiopvapi/resources/shade.py, but I'm not sure what the right representation for the allowed positions is.

Duette Duolite support

I have Duette Duolite shades. These are different shades than the ones referenced in issue #10. My shades are functionally identical to type 8 top-down/bottom-up shades except they have a second fabric extending from the middle rail up to the top rail. I also have a type 8 tdbu and AFAIK my type 8 and type 9 shades control identically. I played with the API as well and the shades match the documented behavior for tdbu shades. Also the information returned by the API for Duette Duolite shades are identical to that returned for my Duette TDBU shade (except for the type value).

Given that I'm pretty sure that the only thing that needs to be done to support this is to declare ShadeTdbu as including type 9, "Duette, Duolite".

Is aiohttp post method implementation correct ?

..Or any other get,put etc method.

https://github.com/sander76/aio-powerview-api/blob/master/aiopvapi/helpers/aiorequest.py#L40

Wondering whether the implementation is according to "best practices".
Especially I am wondering what to do when the reponse is not what it should be.
I can imagine a 404 should be handled differently compared to a timeout error... Or not ? Should I just return "None" or should I raise any kind of exception which I handle higher up in the call stack ?

Test failure

Running the tests fails for me.

============================= test session starts ==============================
platform linux -- Python 3.11.7, pytest-7.4.3, pluggy-1.3.0
rootdir: /build/source
collected 49 items / 1 error                                                   

==================================== ERRORS ====================================
_____________________ ERROR collecting tests/test_shade.py _____________________
ImportError while importing test module '/build/source/tests/test_shade.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
/nix/store/asiphbpiy2gmidfm3xbwcikayhs66289-python3-3.11.7/lib/python3.11/importlib/__init__.py:126: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
tests/test_shade.py:4: in <module>
    from aiopvapi.resources.shade import BaseShade, shade_type
E   ImportError: cannot import name 'shade_type' from 'aiopvapi.resources.shade' (/build/source/aiopvapi/resources/shade.py)
=========================== short test summary info ============================
ERROR tests/test_shade.py
!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!
=============================== 1 error in 0.15s ===============================
/nix/store/v5irq7wvkr7kih0hhnch5nnv2dcq8c4f-stdenv-linux/setup: line 1557: pop_var_context: head of shell_variables not a function context
error: builder for '/nix/store/a48dz96wmmm876zwfk1z2z258dwkbcnb-python3.11-aiopvapi-3.0.1.drv' failed with exit code 2;
       last 10 log lines:
       > /nix/store/asiphbpiy2gmidfm3xbwcikayhs66289-python3-3.11.7/lib/python3.11/importlib/__init__.py:126: in import_module
       >     return _bootstrap._gcd_import(name[level:], package, level)
       > tests/test_shade.py:4: in <module>
       >     from aiopvapi.resources.shade import BaseShade, shade_type
       > E   ImportError: cannot import name 'shade_type' from 'aiopvapi.resources.shade' (/build/source/aiopvapi/resources/shade.py)
       > =========================== short test summary info ============================
       > ERROR tests/test_shade.py
       > !!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!
       > =============================== 1 error in 0.15s ===============================

How to use this with home-assistant

Can you help me how to use this with home assistant? Should I install it as a custom component?
ALso I am looking for a way to isssue the calibrate command. Ths powerview app does have this option, but I can't find it in the API

Tag the source

Could you please tag the source? This allows distributions to get the complete source from GitHub.

PyPi has 1.6.15 while the GitHub release are on 1.6.14.

Thanks

invalid parameter passed to hub when activating scene

This was tested on Home Assistant + aio-powerview-api 1.4
When a scene is activated scene id is passed to the hub using HTTP request. The parameter name should be sceneId instead of sceneid, otherwise hub does nothing. Please see scenes.py:

    @asyncio.coroutine
    def activate_scene(self, scene_id: int):
        """Activate a scene

        :param scene_id: The id of the scene.
        :returns: Nothing.
        """
        yield from self.request.get(self._scenes_path, {"sceneid": scene_id})

I'm not sure if it works with older version of hub (black box). I have a new one (white round one) and it doesn't work.

Tag the source

It would be very helpful if you could tag releases as well again. This would enable distributions who want to fetch the source from GitHub instead of PyPI.

Thanks

test_remove_shade_from_scene fails on 3.1.1

After upgrading from 3.1.0 to 3.1.1 I started seeing the following test failure:

platform linux -- Python 3.12.2, pytest-8.0.2, pluggy-1.4.0

________________ TestSceneMembers.test_remove_shade_from_scene _________________

self = <tests.test_scene_members.TestSceneMembers testMethod=test_remove_shade_from_scene>

    @mock.patch('aiopvapi.helpers.aiorequest.AioRequest.check_response', new=AsyncMock())
    def test_remove_shade_from_scene(self):
        """Tests create new scene."""
        loop = asyncio.get_event_loop()
        request = AioRequest(self.fake_ip, loop)
    
        _del_mock = AsyncMock(return_value=None)
    
        request.websession.delete = _del_mock
    
        async def go():
            scene_members = SceneMembers(request)
            await scene_members.delete_shade_from_scene(1234, 5678)
    
        resp = loop.run_until_complete(go())
>       _del_mock.mock.assert_called_once_with(
            'http://{}/api/scenemembers'.format(self.fake_ip),
            params={"sceneId": 5678,
                    'shadeId': 1234})

tests/test_scene_members.py:39: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/nix/store/fmwqa8nvva4sh18bqayzrilrzxq9fm0f-python3-3.12.2/lib/python3.12/unittest/mock.py:956: in assert_called_once_with
    return self.assert_called_with(*args, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock id='140737311991296'>
args = ('http://123.123.123.123/api/scenemembers',)
kwargs = {'params': {'sceneId': 5678, 'shadeId': 1234}}
expected = call('http://123.123.123.123/api/scenemembers', params={'sceneId': 5678, 'shadeId': 1234})
actual = call('http://123.123.123.123/api/scenemembers', params={'sceneId': 5678, 'shadeId': 1234}, timeout=15)
_error_message = <function NonCallableMock.assert_called_with.<locals>._error_message at 0x7ffff5675e40>
cause = None

    def assert_called_with(self, /, *args, **kwargs):
        """assert that the last call was made with the specified arguments.
    
        Raises an AssertionError if the args and keyword args passed in are
        different to the last call to the mock."""
        if self.call_args is None:
            expected = self._format_mock_call_signature(args, kwargs)
            actual = 'not called.'
            error_message = ('expected call not found.\nExpected: %s\n  Actual: %s'
                    % (expected, actual))
            raise AssertionError(error_message)
    
        def _error_message():
            msg = self._format_mock_failure_message(args, kwargs)
            return msg
        expected = self._call_matcher(_Call((args, kwargs), two=True))
        actual = self._call_matcher(self.call_args)
        if actual != expected:
            cause = expected if isinstance(expected, Exception) else None
>           raise AssertionError(_error_message()) from cause
E           AssertionError: expected call not found.
E           Expected: mock('http://123.123.123.123/api/scenemembers', params={'sceneId': 5678, 'shadeId': 1234})
E             Actual: mock('http://123.123.123.123/api/scenemembers', params={'sceneId': 5678, 'shadeId': 1234}, timeout=15)

/nix/store/fmwqa8nvva4sh18bqayzrilrzxq9fm0f-python3-3.12.2/lib/python3.12/unittest/mock.py:944: AssertionError

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.