# Module `lib.plugins.ambientsound.dfplayer`

Class to drive the dfplayer or yx5300 module

Expand source code

    # Distributed under Pycameresp License
    # Copyright (c) 2023 Remi BERTHOLET
    """ Class to drive the dfplayer or yx5300 module """
    # pylint:disable=consider-using-f-string
    # https://github.com/0xcafed00d/yx5300/blob/master/docs/Serial%20MP3%20Player%20v1.0%20Manual.pdf
    from binascii import hexlify
    import machine

    # Status
    TF_INSERT        = 0x3A  # TF Card was inserted (unsolicited message).
    TF_REMOVE        = 0x3B  # TF card was removed (unsolicited message).
    PLAY_ENDED       = 0x3D  # Track/file has ended (unsolicited message). Data is the index number of the file just completed.
    INIT             = 0x3F  # Initialization complete (unsolicited message). Data is the file store types available (0x02 for TF).
    ERR_FILE         = 0x40  # Error file not found. Data is error code (no definition).
    ACK_OK           = 0x41  # Message acknowledged ok
    STATUS           = 0x42  # Current status. Data high byte is file store (2 for TF); low byte 0=stopped, 1=play, 2=paused.
    VOLUME           = 0x43  # Current volume level. Data is volume level [0..30].
    EQUALIZER        = 0x44  # Equalizer status. Data is equalizer mode types  0=Normal, 1=Pop, 2=Rock, 3=Jazz, 4=Classic or 5=Base.
    TOT_FILES        = 0x48  # TF Total file count
    PLAYING          = 0x4C  # Current file playing
    FLDR_FILES       = 0x4E  # Total number of files in the folder. Data is the number of files.
    TOT_FLDR         = 0x4F  # Total number of folders. Data is the number of folders.

    # Command
    PLAY_NEXT        = 0x01  # Play next song.
    PLAY_PREVIOUS    = 0x02  # Play previous song.
    PLAY_WITH_INDEX  = 0x03  # Play song with index number. Data is the index of the file.
    VOLUME_UP        = 0x04  # Volume increase by one.
    VOLUME_DOWN      = 0x05  # Volume decrease by one.
    SET_VOLUME       = 0x06  # Set the volume to level specified. Data is the volume level [0..30].
    SET_EQUALIZER    = 0x07  # Set the equalizer to specified level. Data is [0..5] ? 0=Normal, 1=Pop, 2=Rock, 3=Jazz, 4=Classic or 5=Base.
    SNG_CYCL_PLAY    = 0x08  # Loop play (repeat) specified track. Data is the track number.
    SEL_DEV          = 0x09  # Select file storage device. The only valid choice for data is TF (0x02).
    SLEEP_MODE       = 0x0A  # Chip enters sleep mode.
    WAKE_UP          = 0x0B  # Chip wakes up from sleep mode.
    RESET            = 0x0C  # Chip reset.
    PLAY             = 0x0D  # Playback restart.
    PAUSE            = 0x0E  # Pause playback.
    PLAY_FOLDER_FILE = 0x0F  # Play the file with the specified folder and index number
    STOP_PLAY        = 0x16  # Stop playback.
    FOLDER_CYCLE     = 0x17  # Loop playback within specified folder. Data is the folder index.
    SHUFFLE_PLAY     = 0x18  # Playback shuffle mode. Data is 0 to enable, 1 to disable.
    SET_SNGL_CYCL    = 0x19  # Set loop play (repeat) on/off for current file. Data is 0 to enable, 1 to disable.
    SET_DAC          = 0x1A  # DAC on/off control (mute sound). Data is 0 to enable DAC, 1 to disable DAC (mute).
    PLAY_W_VOL       = 0x22  # Play track at the specified volume. Data hi byte is the track index, low byte is the volume level [0..30].
    SHUFFLE_FOLDER   = 0x28  # Playback shuffle mode for folder specified. Data high byte is the folder index.
    QUERY_STATUS     = 0x42  # Query Device Status.
    QUERY_VOLUME     = 0x43  # Query Volume level.
    QUERY_EQUALIZER  = 0x44  # Query current equalizer (disabled in hardware).
    QUERY_TOT_FILES  = 0x48  # Query total files in all folders.
    QUERY_PLAYING    = 0x4C  # Query which track playing
    QUERY_FLDR_FILES = 0x4E  # Query total files in folder. Data is the folder index number.
    QUERY_TOT_FLDR   = 0x4F  # Query number of folders.

    class DFPlayer:
            """ Dfplayer """
            def __init__(self, rx=13, tx=4, display=False):
                    """ Open dfplayer instance """
                    self.uart = machine.UART(1, baudrate=9600, rx=rx, tx=tx)
                    self.display = display

            def __del__(self):
                    """ Close dfplayer """
                    if self.uart is not None:
                            self.uart.deinit()

            def checksum(self, frame):
                    """ Compute the frame checksum """
                    result = 0
                    for byte in frame:
                            result -= byte
                    return result

            def send(self, command, param=0, response=False):
                    """ Send command to dfplayer """
                    buf = bytearray(10)
                    buf[0] = 0x7E
                    buf[1] = 0xFF
                    buf[2] = 6
                    buf[3] = command
                    buf[4] = 1 if response else 0
                    buf[5] = (param & 0xFF00) >> 8
                    buf[6] = (param & 0xFF)
                    checksum = self.checksum(buf[1:6])
                    buf[7] = (checksum & 0xFF00) >> 8
                    buf[8] = (checksum & 0xFF)
                    buf[9] = 0xEF
                    if self.display:
                            print("Snd=",hexlify(buf," ").upper().decode("utf8"))
                    self.uart.write(buf)
                    return buf

            def receive(self):
                    """ Receive query response """
                    # The reception is complicated, because it happens that bytes are lost,
                    # and then there is a byte shift on the reception.
                    # In this case, the entire reception buffer is emptied
                    if self.uart.any() > 0:
                            pos = 0
                            command = None
                            data = None
                            fback = None
                            flush = False
                            buffer = b""
                            while self.uart.any() > 0:
                                    char = self.uart.read(1)
                                    buffer += char
                                    if flush is False:
                                            # Start
                                            if pos == 0:
                                                    if char[0] == 0x7E:
                                                            pos += 1
                                                    else:
                                                            flush = True
                                            # Version
                                            elif pos == 1:
                                                    if char[0] == 0xFF:
                                                            pos += 1
                                                    else:
                                                            flush = True
                                            # Length
                                            elif pos == 2:
                                                    if char[0] == 6:
                                                            pos += 1
                                            # Command
                                            elif pos == 3:
                                                    command = char[0]
                                                    pos += 1
                                            # Fback
                                            elif pos == 4:
                                                    fback = char[0]
                                                    pos += 1
                                            # Data high
                                            elif pos == 5:
                                                    data = char[0] << 8
                                                    pos += 1
                                            # Data low
                                            elif pos == 6:
                                                    data |= char[0]
                                                    pos += 1
                                            # Checksum high
                                            elif pos == 7:
                                                    checksum = char[0] << 8
                                                    pos += 1
                                            # Checksum low
                                            elif pos == 8:
                                                    checksum |= char[0]
                                                    pos += 1
                                            # Stop
                                            elif pos == 9:
                                                    if char[0] == 0xEF:
                                                            pos += 1
                                                            break
                                                    else:
                                                            flush = True
                            if pos == 10:
                                    if self.display:
                                            print("Rcv= %02X -> %d"%(command, data))
                                    return command, data
                            else:
                                    if self.display:
                                            print("Bad data received ! %s"%(hexlify(buffer," ").upper().decode("utf8")))
                    return None

            def play(self, response=False):
                    """ Play """
                    if self.display:
                            print("Play")
                    self.send(PLAY, response=response)

            def play_track(self, folder, track, response=False):
                    """ Play """
                    if self.display:
                            print("Play track")
                    self.send(PLAY_FOLDER_FILE, (folder&0xFF) << 8| track, response=response)

            def stop(self, response=False):
                    """ Stop """
                    if self.display:
                            print("Stop")
                    self.send(STOP_PLAY, response=response)

            def pause(self, response=False):
                    """ Pause """
                    if self.display:
                            print("Pause")
                    self.send(PAUSE, response=response)

            def reset(self, response=False):
                    """ Reset """
                    if self.display:
                            print("Reset")
                    self.send(RESET, response=response)

            def play_next(self, response=False):
                    """ Play next """
                    if self.display:
                            print("Next")
                    self.send(PLAY_NEXT, response=response)

            def play_previous(self, response=False):
                    """ Play previous """
                    if self.display:
                            print("Previous")
                    self.send(PLAY_PREVIOUS, response=response)

            def get_status(self):
                    """ Send the get status command """
                    if self.display:
                            print("Get status")
                    self.send(QUERY_STATUS, response=True)

## Classes

`class DFPlayer (rx=13, tx=4, display=False)`

  Dfplayer

  Open dfplayer instance

  Expand source code

      class DFPlayer:
              """ Dfplayer """
              def __init__(self, rx=13, tx=4, display=False):
                      """ Open dfplayer instance """
                      self.uart = machine.UART(1, baudrate=9600, rx=rx, tx=tx)
                      self.display = display

              def __del__(self):
                      """ Close dfplayer """
                      if self.uart is not None:
                              self.uart.deinit()

              def checksum(self, frame):
                      """ Compute the frame checksum """
                      result = 0
                      for byte in frame:
                              result -= byte
                      return result

              def send(self, command, param=0, response=False):
                      """ Send command to dfplayer """
                      buf = bytearray(10)
                      buf[0] = 0x7E
                      buf[1] = 0xFF
                      buf[2] = 6
                      buf[3] = command
                      buf[4] = 1 if response else 0
                      buf[5] = (param & 0xFF00) >> 8
                      buf[6] = (param & 0xFF)
                      checksum = self.checksum(buf[1:6])
                      buf[7] = (checksum & 0xFF00) >> 8
                      buf[8] = (checksum & 0xFF)
                      buf[9] = 0xEF
                      if self.display:
                              print("Snd=",hexlify(buf," ").upper().decode("utf8"))
                      self.uart.write(buf)
                      return buf

              def receive(self):
                      """ Receive query response """
                      # The reception is complicated, because it happens that bytes are lost,
                      # and then there is a byte shift on the reception.
                      # In this case, the entire reception buffer is emptied
                      if self.uart.any() > 0:
                              pos = 0
                              command = None
                              data = None
                              fback = None
                              flush = False
                              buffer = b""
                              while self.uart.any() > 0:
                                      char = self.uart.read(1)
                                      buffer += char
                                      if flush is False:
                                              # Start
                                              if pos == 0:
                                                      if char[0] == 0x7E:
                                                              pos += 1
                                                      else:
                                                              flush = True
                                              # Version
                                              elif pos == 1:
                                                      if char[0] == 0xFF:
                                                              pos += 1
                                                      else:
                                                              flush = True
                                              # Length
                                              elif pos == 2:
                                                      if char[0] == 6:
                                                              pos += 1
                                              # Command
                                              elif pos == 3:
                                                      command = char[0]
                                                      pos += 1
                                              # Fback
                                              elif pos == 4:
                                                      fback = char[0]
                                                      pos += 1
                                              # Data high
                                              elif pos == 5:
                                                      data = char[0] << 8
                                                      pos += 1
                                              # Data low
                                              elif pos == 6:
                                                      data |= char[0]
                                                      pos += 1
                                              # Checksum high
                                              elif pos == 7:
                                                      checksum = char[0] << 8
                                                      pos += 1
                                              # Checksum low
                                              elif pos == 8:
                                                      checksum |= char[0]
                                                      pos += 1
                                              # Stop
                                              elif pos == 9:
                                                      if char[0] == 0xEF:
                                                              pos += 1
                                                              break
                                                      else:
                                                              flush = True
                              if pos == 10:
                                      if self.display:
                                              print("Rcv= %02X -> %d"%(command, data))
                                      return command, data
                              else:
                                      if self.display:
                                              print("Bad data received ! %s"%(hexlify(buffer," ").upper().decode("utf8")))
                      return None

              def play(self, response=False):
                      """ Play """
                      if self.display:
                              print("Play")
                      self.send(PLAY, response=response)

              def play_track(self, folder, track, response=False):
                      """ Play """
                      if self.display:
                              print("Play track")
                      self.send(PLAY_FOLDER_FILE, (folder&0xFF) << 8| track, response=response)

              def stop(self, response=False):
                      """ Stop """
                      if self.display:
                              print("Stop")
                      self.send(STOP_PLAY, response=response)

              def pause(self, response=False):
                      """ Pause """
                      if self.display:
                              print("Pause")
                      self.send(PAUSE, response=response)

              def reset(self, response=False):
                      """ Reset """
                      if self.display:
                              print("Reset")
                      self.send(RESET, response=response)

              def play_next(self, response=False):
                      """ Play next """
                      if self.display:
                              print("Next")
                      self.send(PLAY_NEXT, response=response)

              def play_previous(self, response=False):
                      """ Play previous """
                      if self.display:
                              print("Previous")
                      self.send(PLAY_PREVIOUS, response=response)

              def get_status(self):
                      """ Send the get status command """
                      if self.display:
                              print("Get status")
                      self.send(QUERY_STATUS, response=True)

  ### Methods

  `def checksum(self, frame)`

    Compute the frame checksum

    Expand source code

        def checksum(self, frame):
                """ Compute the frame checksum """
                result = 0
                for byte in frame:
                        result -= byte
                return result

  `def get_status(self)`

    Send the get status command

    Expand source code

        def get_status(self):
                """ Send the get status command """
                if self.display:
                        print("Get status")
                self.send(QUERY_STATUS, response=True)

  `def pause(self, response=False)`

    Pause

    Expand source code

        def pause(self, response=False):
                """ Pause """
                if self.display:
                        print("Pause")
                self.send(PAUSE, response=response)

  `def play(self, response=False)`

    Play

    Expand source code

        def play(self, response=False):
                """ Play """
                if self.display:
                        print("Play")
                self.send(PLAY, response=response)

  `def play_next(self, response=False)`

    Play next

    Expand source code

        def play_next(self, response=False):
                """ Play next """
                if self.display:
                        print("Next")
                self.send(PLAY_NEXT, response=response)

  `def play_previous(self, response=False)`

    Play previous

    Expand source code

        def play_previous(self, response=False):
                """ Play previous """
                if self.display:
                        print("Previous")
                self.send(PLAY_PREVIOUS, response=response)

  `def play_track(self, folder, track, response=False)`

    Play

    Expand source code

        def play_track(self, folder, track, response=False):
                """ Play """
                if self.display:
                        print("Play track")
                self.send(PLAY_FOLDER_FILE, (folder&0xFF) << 8| track, response=response)

  `def receive(self)`

    Receive query response

    Expand source code

        def receive(self):
                """ Receive query response """
                # The reception is complicated, because it happens that bytes are lost,
                # and then there is a byte shift on the reception.
                # In this case, the entire reception buffer is emptied
                if self.uart.any() > 0:
                        pos = 0
                        command = None
                        data = None
                        fback = None
                        flush = False
                        buffer = b""
                        while self.uart.any() > 0:
                                char = self.uart.read(1)
                                buffer += char
                                if flush is False:
                                        # Start
                                        if pos == 0:
                                                if char[0] == 0x7E:
                                                        pos += 1
                                                else:
                                                        flush = True
                                        # Version
                                        elif pos == 1:
                                                if char[0] == 0xFF:
                                                        pos += 1
                                                else:
                                                        flush = True
                                        # Length
                                        elif pos == 2:
                                                if char[0] == 6:
                                                        pos += 1
                                        # Command
                                        elif pos == 3:
                                                command = char[0]
                                                pos += 1
                                        # Fback
                                        elif pos == 4:
                                                fback = char[0]
                                                pos += 1
                                        # Data high
                                        elif pos == 5:
                                                data = char[0] << 8
                                                pos += 1
                                        # Data low
                                        elif pos == 6:
                                                data |= char[0]
                                                pos += 1
                                        # Checksum high
                                        elif pos == 7:
                                                checksum = char[0] << 8
                                                pos += 1
                                        # Checksum low
                                        elif pos == 8:
                                                checksum |= char[0]
                                                pos += 1
                                        # Stop
                                        elif pos == 9:
                                                if char[0] == 0xEF:
                                                        pos += 1
                                                        break
                                                else:
                                                        flush = True
                        if pos == 10:
                                if self.display:
                                        print("Rcv= %02X -> %d"%(command, data))
                                return command, data
                        else:
                                if self.display:
                                        print("Bad data received ! %s"%(hexlify(buffer," ").upper().decode("utf8")))
                return None

  `def reset(self, response=False)`

    Reset

    Expand source code

        def reset(self, response=False):
                """ Reset """
                if self.display:
                        print("Reset")
                self.send(RESET, response=response)

  `def send(self, command, param=0, response=False)`

    Send command to dfplayer

    Expand source code

        def send(self, command, param=0, response=False):
                """ Send command to dfplayer """
                buf = bytearray(10)
                buf[0] = 0x7E
                buf[1] = 0xFF
                buf[2] = 6
                buf[3] = command
                buf[4] = 1 if response else 0
                buf[5] = (param & 0xFF00) >> 8
                buf[6] = (param & 0xFF)
                checksum = self.checksum(buf[1:6])
                buf[7] = (checksum & 0xFF00) >> 8
                buf[8] = (checksum & 0xFF)
                buf[9] = 0xEF
                if self.display:
                        print("Snd=",hexlify(buf," ").upper().decode("utf8"))
                self.uart.write(buf)
                return buf

  `def stop(self, response=False)`

    Stop

    Expand source code

        def stop(self, response=False):
                """ Stop """
                if self.display:
                        print("Stop")
                self.send(STOP_PLAY, response=response)