Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow defining device_id for push server #1710

Merged
merged 2 commits into from Feb 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 5 additions & 5 deletions miio/devtools/simulators/common.py
Expand Up @@ -27,14 +27,14 @@ def create_info_response(model, addr, mac):
return INFO_RESPONSE


def mac_from_model(model):
"""Creates a mac address based on the model name.
def did_and_mac_for_model(model):
"""Creates a device id and a mac address based on the model name.

This allows simulating multiple different devices separately as the homeassistant
unique_id is based on the mac address.
These identifiers allow making a simulated device unique for testing.
"""
m = md5() # nosec
m.update(model.encode())
digest = m.hexdigest()[:12]
did = int(digest[:8], base=16)
mac = ":".join([digest[i : i + 2] for i in range(0, len(digest), 2)])
return mac
return did, mac
8 changes: 4 additions & 4 deletions miio/devtools/simulators/miiosimulator.py
Expand Up @@ -10,7 +10,7 @@

from miio import PushServer

from .common import create_info_response, mac_from_model
from .common import create_info_response, did_and_mac_for_model

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -135,13 +135,13 @@ def handle_set(self, payload):


async def main(dev):
server = PushServer()
did, mac = did_and_mac_for_model(dev)
server = PushServer(device_id=did)

_ = MiioSimulator(dev=dev, server=server)
mac = mac_from_model(dev._model)
server.add_method("miIO.info", create_info_response(dev._model, "127.0.0.1", mac))

transport, proto = await server.start()
await server.start()


@click.command()
Expand Down
7 changes: 3 additions & 4 deletions miio/devtools/simulators/miotsimulator.py
Expand Up @@ -12,7 +12,7 @@
from miio.miot_cloud import MiotCloud
from miio.miot_models import DeviceModel, MiotAccess, MiotProperty, MiotService

from .common import create_info_response, mac_from_model
from .common import create_info_response, did_and_mac_for_model

_LOGGER = logging.getLogger(__name__)
UNSET = -10000
Expand Down Expand Up @@ -248,9 +248,8 @@ def action(self, payload):


async def main(dev, model):
server = PushServer()

mac = mac_from_model(model)
device_id, mac = did_and_mac_for_model(model)
server = PushServer(device_id=device_id)
simulator = MiotSimulator(device_model=dev)
server.add_method("miIO.info", create_info_response(model, "127.0.0.1", mac))
server.add_method("action", simulator.action)
Expand Down
11 changes: 6 additions & 5 deletions miio/push_server/server.py
Expand Up @@ -54,13 +54,14 @@ class PushServer:
await push_server.stop()
"""

def __init__(self, device_ip=None):
def __init__(self, *, device_ip=None, device_id=None):
"""Initialize the class."""
self._device_ip = device_ip

self._address = "0.0.0.0" # nosec
self._server_ip = None
self._server_id = int(FAKE_DEVICE_ID)

self._device_id = device_id if device_id is not None else int(FAKE_DEVICE_ID)
self._server_model = FAKE_DEVICE_MODEL

self._loop = None
Expand Down Expand Up @@ -282,7 +283,7 @@ def _construct_event( # nosec

target_data = {
"command": command,
"did": str(self.server_id),
"did": str(self.device_id),
"extra": info.command_extra,
"id": message_id,
"ip": self.server_ip,
Expand Down Expand Up @@ -316,9 +317,9 @@ def server_ip(self):
return self._server_ip

@property
def server_id(self):
def device_id(self):
"""Return the ID of the fake device beeing emulated."""
return self._server_id
return self._device_id

@property
def server_model(self):
Expand Down
8 changes: 4 additions & 4 deletions miio/push_server/serverprotocol.py
Expand Up @@ -32,7 +32,7 @@ def _build_ack(self):
timestamp = calendar.timegm(datetime.datetime.now().timetuple())
# ACK packet not signed, 16 bytes header + 16 bytes of zeroes
return struct.pack(
">HHIII16s", 0x2131, 32, 0, self.server.server_id, timestamp, bytes(16)
">HHIII16s", 0x2131, 32, 0, self.server.device_id, timestamp, bytes(16)
)

def connection_made(self, transport):
Expand All @@ -42,7 +42,7 @@ def connection_made(self, transport):
_LOGGER.info(
"Miio push server started with address=%s server_id=%s",
self.server._address,
self.server.server_id,
self.server.device_id,
)

def connection_lost(self, exc):
Expand All @@ -54,7 +54,7 @@ def send_ping_ACK(self, host, port):
_LOGGER.debug("%s:%s=>PING", host, port)
m = self._build_ack()
self.transport.sendto(m, (host, port))
_LOGGER.debug("%s:%s<=ACK(server_id=%s)", host, port, self.server.server_id)
_LOGGER.debug("%s:%s<=ACK(server_id=%s)", host, port, self.server.device_id)

def _create_message(self, data, token, device_id):
"""Create a message to be sent to the client."""
Expand All @@ -78,7 +78,7 @@ def send_response(self, host, port, msg_id, token, payload=None):
payload = {}

data = {**payload, "id": msg_id}
msg = self._create_message(data, token, device_id=self.server.server_id)
msg = self._create_message(data, token, device_id=self.server.device_id)

self.transport.sendto(msg, (host, port))
_LOGGER.debug(">> %s:%s: %s", host, port, data)
Expand Down
6 changes: 3 additions & 3 deletions miio/push_server/test_serverprotocol.py
Expand Up @@ -11,7 +11,7 @@

HOST = "127.0.0.1"
PORT = 1234
SERVER_ID = 4141
DEVICE_ID = 4141
DUMMY_TOKEN = bytes.fromhex("0" * 32)


Expand All @@ -20,7 +20,7 @@ def protocol(mocker, event_loop) -> ServerProtocol:
server = mocker.Mock()

# Mock server id
type(server).server_id = mocker.PropertyMock(return_value=SERVER_ID)
type(server).device_id = mocker.PropertyMock(return_value=DEVICE_ID)
socket = mocker.Mock()

proto = ServerProtocol(event_loop, socket, server)
Expand All @@ -37,7 +37,7 @@ def test_send_ping_ack(protocol: ServerProtocol, mocker):
cargs = protocol.transport.sendto.call_args[0]

m = Message.parse(cargs[0])
assert int.from_bytes(m.header.value.device_id, "big") == SERVER_ID
assert int.from_bytes(m.header.value.device_id, "big") == DEVICE_ID
assert m.data.length == 0

assert cargs[1][0] == HOST
Expand Down