mattsaxon / HASS-SpeakercraftMediaPlayer

Speakercraft Platform for Home Assistant
4 stars 1 forks source link

Quick commands sent at once and fail. #11

Closed sjeffrey101 closed 2 years ago

sjeffrey101 commented 2 years ago

When sending multiple commands at once it only processes the first.

this can be replicated by using and automation to turn on 2 zones at once. or pressing volume up very quickly.

It also means that the default volume doesnt work as it sends the set volume directly after turning off a zone.

What is happening is that the second command is added to the write buffer and then transmitted all together in a single command window. The first command is recognised and confirmed, the following commands are ignored.

mattsaxon commented 2 years ago

I wonder if a flush command might address this?

sjeffrey101 commented 2 years ago

Trying to resolve this i have recreated a command queue, to wait until the previous command is confirmed. Once added to the queue it tries to send it, but only if the write buffer is empty. Otherwise it waits. This fix doesnt work, but not sure why.


    def send_command(self, command: bytes):
            _LOGGER.warn("Adding Command To Queue " + bytes(command).hex())
            self.commandqueue.append(command)
            self.send_command_write()
            #self._writer.write(command)

    def send_command_write(self):
            #_LOGGER.warn("SC Buffer " + str(self._writer.transport.get_write_buffer_size()))

            if self.commandqueue:
                _LOGGER.warn("SC Buffer " + str(self._writer.transport.get_write_buffer_size()))
                if self._writer.transport.get_write_buffer_size() == 0:
                    command=self.commandqueue.pop()
                    _LOGGER.warn("Sending Command " + bytes(command).hex())
                    self._writer.write(command)

I also add self.send_command_write() to the bottom of the serial runner while loop, so it should attempt to send after confirmation of the previous command is recieved.

But it doesnt seem to be working.

with the debug i get the following

Adding Command To Queue 5504a107ff SC Buffer 0 Sending Command 5504a107ff Adding Command To Queue 55085700000536070a SC Buffer 5 Confirmation 550595a101 SC Buffer 0 Sending Command 55085700000536070a

so it looks like it should work. as it waits to send the 2nd command, but it doesnt seem to send it, i dont get a confirmaiton.

sjeffrey101 commented 2 years ago

I wonder if a flush command might address this?

i dont think that will work. as it cant flush until the window.

i was wondering if that is what drain() is for - but this seems to block my code indefinatly.

sjeffrey101 commented 2 years ago

i'll have another look tonight.

whats the best way of uploading work in progress code to github which isnt committed, but allows someone else to pull it down to see how it works. eg rather then pasting snippets above, it would be easier for you to see the whole file.

mattsaxon commented 2 years ago

You should fork the repository so you have your own copy and then keep discrete branches for your work in progress. If you only want one piece of work on progress, you can just leave it on the main branch. When you want me to merge it with the main code (currently in my repo), you issue a pull request which invites me to merge and offers review functionality. Therefore it sometimes makes sense to issue a PR even if you don’t expect it to be merged.

mattsaxon commented 2 years ago

i was wondering if that is what drain() is for - but this seems to block my code indefinatly.

Are you issuing the "Await self._writer.drain()" command, according to the docs, this waits until it drains to the low watermark (not sure what that is), but it is a non blocking call when used with "await"

sjeffrey101 commented 2 years ago

drain doesnt seem to make much difference. Ive changed all the functions to async, so i can await drain. But still makes no difference. only time ive had it working is if i sleep for 1 second.

I dont understand why my queueing isnt working. as its waiting until the buffer is 0 before sending. Ive also made it wait until the previous confirmation is recieved.

Problem is im not sure if its the reciever ignoring the command or the async_serial flowcontrol missing the window.

I wish there was some way of watching the serial port send/recieve without messing the code.

mattsaxon commented 2 years ago

I suspect this is because the low water mark is greater than zero. See set_write_buffer_limits(self, high=None, low=None) of pyserial_asyncio. Sorry I can't try any of this out as I am away from my development environment for a while.

Yes its a pity you can't see the lower level data exchange I agree. I'm not sure how to achieve that.

sjeffrey101 commented 2 years ago

ive tried lots of different values for high and low including 0. Seems not to make any difference.

i cant seem to get it to send this command correctly.