Utilisation de melodie de type rtttl

Parfait, sur quel topic ?

As-tu essayé d’envoyer la même chose sur le même topic avec une commande action depuis JMQTT ?

Lorsque j’envoi la commande depuis Jeedom , sous Mqtt explorer j’ai la réponse ’ Nextion ’ 'done ’ et le résultat est affiché avec une suite de carré mais pas de son .

Toutes les autres fonction de commande fonctionne sous le topic action

J’ai ouvert un autre post pour la fonction rtttl car je pense que le plus simple serait de modifier le programme initial et d’y inclure directement la fonction rttttl ou de pouvoir créer un lien vers la fonction rtttl

Le nspanel est à base d’un esp32 qui communique avec un ecran Nextion , le buzzer est sur la carte principale de l’esp32

L’envoi de la commande sous JMQTT est peut etre bonne , elle n’est juste simplement pas correctement interprété par le nspanel car la fonction rtttl n’est pas intégrée dans le programme de base . Ce qu’il l’est dans le programme HA .

Est-ce que tu es sur que tu publies exactement la même chose ?

Si tout est interfacé en mqtt entre HA et l’ESP, il suffit d’écouter ce que HA envoie et d’envoyer exactement la même chose depuis Jeedom/jMQTT.

Peux-tu me mettre des captures de ce qui se passe (quand tu joues la mélodie) dans MQTT Explorer, mais aussi des logs en debug de jMQTTd en écoute sur ce topic à ce moment là ?
J’aurais aussi besoin d’une capture de la commande de action que tu utilises dans jMQTT pour jouer la mélodie et les logs de jMQTTd (toujours en debug) à ce moment là.

Merci

Ok , je vais te préparer toute ces infos .
je fait du copier coller pour mes action dans JMQTT , donc je pense que les actions sont conforme à la commande originale .
Je m’en occupe dans la journée ,
merci pour ton retour

Bonjour
@Bad , j’ai trouvé d’autres info sur mon soucis de transfert d’info rtttl par JMQTT .
De base dans le firmware tasmota du nspanel la fonction buzzer est activée comme un buzzer .
Dans HA la fonction buzzer est activée en fonction buzzer LEDC PWM (firmware spécifique), ce qui permet la modulation de fréquence et donc les mélodies .
Ce n’est pas un problème de transmission d’info via JMQTT , quelque soit la syntaxe . C’est pour cela que l’info est envoyée au nspanel mais pas interprété correctement par le programme du nspanel .
Je dois donc trouver comment modifier le fichier de base du nspanel pour intégrer la fonction buzzer LEDC .
Merci pout ton aide , je poursuis ma quette .
J’ai aussi fait la demande dans l’autre post que j’ai ouvert pour une aide pour la modification du programme .
Le post initial du nspanel semble etre à l’arret ou en panne d’inspiration .

Je ne pense pas que modifier le firmware du NSpanel soit la solution.

Dit-moi si je me trompe, mais tu arrive à faire ce que tu veux (rtttl) avec HA ?
N’ayant pas de NSpanel, je ne sais pas ce qui est échangé entre 2 pour ça, peux-tu envoyer les logs que demandés plus haut ? A partir de ces derniers, il sera certainement possible de trouver comment HA fait pour jouer les mélodies et reprendre ce fonctionnement sur Jeedom.

Effectivement avec HA , tu rentres la mélodie dans la ligne de commande , tu valides , et lorsque l’appel de la fonction est demandé la melodie est lue .
Lorsque l’on regarde dans le programme Yaml on appel la fonction play-rtttl lors d’une commande .
Pour les tests avec HA je vais avoir besoin d’un petit peu de temps car en fait je dois ré injecter le firmware HA dans le nspanel , le ré-attribuer dans ESPHOME de HA , refaire les test sous HA , remettre le firmware tasmota , recharger le HMI Nextion pour qu’il soit à nouveau opérationel sous Jeedom . …

Programme Yaml

sai# Set some variables for convenience
substitutions:
  node_name: nspanel-demo
  device_name: Demo NSPanel

# Note: this may not be needed if the pull request has been merged.
# Check https://github.com/esphome/esphome/pull/2956 for current status.
external_components:
  - source: github://pr#2956
    components: [nextion]
    refresh: 1h

esphome:
  name: $node_name
  comment: $device_name

esp32:
  board: esp32dev

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

# Enable logging
logger:

# Enable wireless updates
ota:

# Enable Home Assistant API
api:
  services:
    # Service to play a song
    - service: play_rtttl
      variables:
        song_str: string
      then:
        - rtttl.play:
            rtttl: !lambda 'return song_str;'
    - service: upload_tft
      then:
        - lambda: 'id(disp1)->upload_tft();'

# A reboot button is always useful
button:
  - platform: restart
    name: Restart $device_name

# Define some inputs
binary_sensor:
  - platform: gpio
    name: $device_name Left Button
    pin:
      number: 14
      inverted: true
    on_click:
      - switch.toggle: relay_1

  - platform: gpio
    name: $device_name Right Button
    pin:
      number: 27
      inverted: true
    on_click:
      - switch.toggle: relay_2
  
  - platform: nextion
    name: $device_name Play Button
    page_id: 0
    component_id: 2

  - platform: nextion
    name: $device_name On Button
    page_id: 0
    component_id: 3

  - platform: nextion
    name: $device_name Off Button
    page_id: 0
    component_id: 4

  - platform: nextion
    name: $device_name Red Button
    page_id: 0
    component_id: 6

sensor:
  - platform: wifi_signal
    name: $device_name WiFi Signal
    update_interval: 60s

  - platform: ntc
    id: temperature
    sensor: resistance_sensor
    calibration:
      b_constant: 3950
      reference_temperature: 25°C
      reference_resistance: 10kOhm
    name: $device_name Temperature

  - platform: resistance
    id: resistance_sensor
    sensor: ntc_source
    configuration: DOWNSTREAM
    resistor: 11.2kOhm

  - platform: adc
    id: ntc_source
    pin: 38
    update_interval: 10s
    attenuation: 11db

  # Grab current temperature from Home Assistant
  - platform: homeassistant
    id: current_temperature
    entity_id: weather.home
    attribute: temperature
    on_value:
      # Push it to the display
      then:
        - lambda: 'id(disp1).set_component_text_printf("temp", "%.1f ""\xb0""F", x);'

# Define some outputs
switch:
  # The two relays
  - platform: gpio
    name: $device_name Relay 1
    id: relay_1
    pin:
      number: 22
  - platform: gpio
    name: $device_name Relay 2
    id: relay_2
    pin:
      number: 19

  # Pin 4 always needs to be on to power up the display
  - platform: gpio
    id: screen_power
    entity_category: config
    pin:
      number: 4
      inverted: true
    restore_mode: ALWAYS_ON

number:
  platform: template
  name: $device_name Brightness
  id: brightness
  entity_category: config
  unit_of_measurement: '%'
  min_value: 0
  max_value: 100
  step: 1
  initial_value: 30
  set_action:
    then:
      - lambda: 'id(disp1).set_backlight_brightness(x/100);'

# Configure the internal bleeper
output:
  - platform: ledc
    id: buzzer_out
    pin:
      number: 21

# Enable ringtone music support
rtttl:
  id: buzzer
  output: buzzer_out

# Configure UART for communicating with the screen
uart:
  id: tf_uart
  tx_pin: 16
  rx_pin: 17
  baud_rate: 115200

# Configure the screen itself
display:
  - platform: nextion
    id: disp1
    uart_id: tf_uart
    tft_url: http://your-home-assistant-ip-here:8123/local/nspanel_demo.tft
    # A little fun...
    on_setup:
      then:
        - number.set:
            id: brightness
            value: 30
        - lambda: |-
            id(disp1).set_component_text_printf(
              "temp", "%.1f ""\xb0""F", id(current_temperature).state
            );
        - rtttl.play: "twobits:d=4,o=5,b=220:c6,8g,8g,a,g,p,b,c6"sissez ou collez du code ici

mon programme nspanel

# Sonoff NSPanel Tasmota driver 
# based on;
# Sonoff NSPanel Tasmota (Nextion with Flashing) driver | code by peepshow-21
# Sonoff NSPanel Tasmota driver v0.47 | code by blakadder and s-hadinger

class Nextion : Driver

    static VERSION = "v1.0.0-beta1"
    static CHUNK_FILE = "nextion"
    static header = bytes().fromstring("PS")

    var flash_mode
    var ser
    var chunk_url
    var flash_size
    var chunk
    var tot_read
    var last_per

    def split_msg(b)   
        import string
        var ret = []
        var i = 0
        while i < size(b)-1
            if b[i] == 0x55 && b[i+1] == 0xAA
                if i > 0
                    var nb = b[0..i-1];
                    ret.push(nb)
                end
                b = b[i+2..]
                i = 0
            else
                i+=1
            end
        end
        if size(b) > 0
            ret.push(b)
        end
        return ret
    end

    def crc16(data, poly)
      if !poly  poly = 0xA001 end
      # CRC-16 MODBUS HASHING ALGORITHM
      var crc = 0xFFFF
      for i:0..size(data)-1
        crc = crc ^ data[i]
        for j:0..7
          if crc & 1
            crc = (crc >> 1) ^ poly
          else
            crc = crc >> 1
          end
        end
      end
      return crc
    end

    def encode(payload)
      var b = bytes()
      b += self.header
      var nsp_type = 0 # not used
      b.add(nsp_type)       # add a single byte
      b.add(size(payload), 2)   # add size as 2 bytes, little endian
      b += bytes().fromstring(payload)
      var msg_crc = self.crc16(b)
      b.add(msg_crc, 2)       # crc 2 bytes, little endian
      return b
    end

    def encodenx(payload)
        var b = bytes().fromstring(payload)
        b += bytes('FFFFFF')
        return b
    end

    def sendnx(payload)
        import string
        var payload_bin = self.encodenx(payload)
        self.ser.write(payload_bin)
        log(string.format("NSP: Nextion command sent = %s",str(payload_bin)), 3)       
    end

    def send(payload)
        var payload_bin = self.encode(payload)
        if self.flash_mode==1
            log("NSP: skipped command becuase still flashing", 3)
        else 
            self.ser.write(payload_bin)
            log("NSP: payload sent = " + str(payload_bin), 3)
        end
    end

    def getPage(url)
        var s
        var retry = 0
        while (retry>=0 && retry<5)
            var wc = webclient()
            wc.begin(url)
            var r = wc.GET()
            if (r==200)
                s = wc.get_string()
                retry = -1
            else
                s = nil
                retry = retry + 1
                log("NSP: HTTP retry required")
            end
            wc.close()
        end
        if (s==nil) 
            log("NSP: Failed to load chunk over http")
        end
        return s    
    end

    def write_to_file(b)
        log("DBG: Write to file")
        var f = open("test.bin","a")
        f.write(b)
        f.close()
    end

    def write_to_nextion(b)
        self.ser.write(b)
    end

    def write_chunk()
        import string
        var name = string.format("%s/%s-%04d.hex",self.chunk_url,self.CHUNK_FILE,self.chunk)
        var s = self.getPage(name)
        var b = bytes(s)
        #self.write_to_file(b)
        self.write_to_nextion(b)
        return b.size()
    end

    def init()
        log("NSP: Initializing Driver")
        self.ser = serial(17, 16, 115200, serial.SERIAL_8N1)
        self.sendnx('DRAKJHSUYDGBNCJHGJKSHBDN')
        self.flash_mode = 0
    end

    def screeninit()
        log("NSP: Screen Initialized") 
        self.set_power()
        self.set_clock()
    end


#
 #   def every_second()
 #       var now = tasmota.rtc()
 #       var time_raw = now['local']
 #       var nsp_time = tasmota.time_dump(time_raw)
        #var time_playload = 'page0.x0.val=' + str(nsp_time['year']) + str(nsp_time['month']) + str(nsp_time['day']) + str(nsp_time['hour']) + str(nsp_time['min']) + str(nsp_time['weekday'])
 #       var time_playload = 'page0.t0.txt=\"' + str(nsp_time['hour']) + ':' + str(nsp_time['min']) + ':' + str(nsp_time['sec']) + '\"' 

  #      self.sendnx(time_playload)
        #tasmota.publish_result(time_playload, "RESULT")
  #  end



    def every_100ms()
        import string
        if self.ser.available() > 0
            var msg = self.ser.read()
            if size(msg) > 0
                log(string.format("NSP: Received Raw = %s",str(msg)), 3)
                if (self.flash_mode==1)
                    var str = msg[0..-4].asstring()
                    log(str, 3)
                    if (string.find(str,"comok 2")==0) 
                        self.sendnx(string.format("whmi-wri %d,115200,res0",self.flash_size))
                    elif (size(msg)==1 && msg[0]==0x05)
                        var x = self.write_chunk()
                        self.tot_read = self.tot_read + x
                        self.chunk = self.chunk + 1
                        var per = (self.tot_read*100)/self.flash_size
                        if (self.last_per!=per) 
                            self.last_per = per
                            tasmota.publish_result(string.format("{\"Flashing\":{\"complete\": %d}}",per), "RESULT") 
                        end
                        if (self.tot_read==self.flash_size)
                            log("NSP: Flashing complete")
                            self.flash_mode = 0
                        end
                        tasmota.yield()
                    end
                else
                    var msg_list = self.split_msg(msg)
                    for i:0..size(msg_list)-1
                        msg = msg_list[i]
                        if size(msg) > 0
                            if msg == bytes('000000FFFFFF88FFFFFF')
                                self.screeninit()
                            elif msg[0]==0x7B # JSON, starting with "{"
                                var jm = string.format("%s",msg[0..-1].asstring())
                                tasmota.publish_result(jm, "RESULT")        
                            elif msg[0]==0x07 && size(msg)==1 # BELL/Buzzer
                                tasmota.cmd("buzzer 1,1")
                            else
                            
                            #   var jm = string.format("{\"nextion\":\"%s\"}",str(msg[0..-4]))
                            #   var jm = string.format("{\"nextion\":\"%s\"}",str(msg[0..-4]))
                                var jm = msg.asstring() #message pour Jeedom

                                if jm == "switch1_true"
                                    tasmota.set_power(0, true)
                                elif jm == "switch1_false"
                                     tasmota.set_power(0, false)
                                elif jm == "switch2_true"
                                     tasmota.set_power(1, true)
                                elif jm == "switch2_false"
                                     tasmota.set_power(1, false)
                                end





                                tasmota.publish_result(jm, "RESULT")        
                            end
                        end       
                    end
                end
            end
        end
    end      

    def begin_file_flash()
        self.flash_mode = 1
        var f = open("test.bin","w")
        f.close()
        while self.tot_read<self.flash_size
            var x = self.write_chunk()
            self.tot_read = self.tot_read + x
            self.chunk = self.chunk + 1
            tasmota.yield()
        end        
    end

    def begin_nextion_flash()
        self.sendnx('DRAKJHSUYDGBNCJHGJKSHBDN')
        self.sendnx('recmod=0')
        self.sendnx('recmod=0')
        self.sendnx("connect")        
        self.flash_mode = 1
    end
    
    def start_flash(url)
        self.last_per = -1
        self.chunk_url = url
        import string
        var file = (string.format("%s/%s.txt",self.chunk_url,self.CHUNK_FILE))
        var s = self.getPage(file)
        self.flash_size = int(s)
        self.tot_read = 0
        self.chunk = 0
        #self.begin_file_flash()
        self.begin_nextion_flash()
    end

    def set_power()   
        var ps = tasmota.get_power()
        if ps[0] == true
            self.sendnx('switch1=1')
        else 
            self.sendnx('switch1=0')
        end
        if ps[1] == true
            self.sendnx('switch2=1')
        else 
            self.sendnx('switch2=0')
        end
        #var tmp = tasmota.set_temp()
        #tasmota.publish_result(tmp, "RESULT")
    end

    def set_clock()
        var now = tasmota.rtc()
        var time_raw = now['local']
        var raw_playload = 'systime=' + str(now['local'])
        self.sendnx(raw_playload)


        var nsp_time = tasmota.time_dump(time_raw)
        #var time_payload = '{ "clock": { "date":' + str(nsp_time['day']) + ',"month":' + str(nsp_time['month']) + ',"year":' + str(nsp_time['year']) + ',"weekday":' + str(nsp_time['weekday']) + ',"hour":' + str(nsp_time['hour']) + ',"min":' + str(nsp_time['min']) + ' } }'
        #log('NSP: Time and date synced with ' + time_payload, 3)
        #self.send(time_payload)

        #var time_playload = 'page0.t0.txt=\"' + str(nsp_time['hour']) + ':' + str(nsp_time['min']) + '\"' 

        var time_playload = 'page0.t0.txt=\"'
        if nsp_time['hour'] < 10
            time_playload = time_playload + '0'
        end
        time_playload = time_playload + str(nsp_time['hour']) + ':'
        if nsp_time['min'] < 10
            time_playload = time_playload + '0'
        end
        time_playload = time_playload + str(nsp_time['min']) + '\"'

        self.sendnx(time_playload)
    end

end

var nextion = Nextion()

tasmota.add_driver(nextion)

def set_temp(value)
  var temp_ajust = value 
  temp_ajust = temp_ajust * 10
  var temp_payload = 'page0.x1.val=' + str(temp_ajust) 
  log('NSP: Indoor temperature set with ' + temp_payload, 3)
  tasmota.publish_result(temp_payload, "RESULT")
  nextion.sendnx(temp_payload)
end

tasmota.add_rule("Tele#ANALOG#Temperature1", set_temp) # rule to run set_temp on teleperiod

def flash_nextion(cmd, idx, payload, payload_json)
    def task()
        nextion.start_flash(payload)
    end
    tasmota.set_timer(0,task)
    tasmota.resp_cmnd_done()
end

tasmota.add_cmd('FlashNextion', flash_nextion)

def send_cmd(cmd, idx, payload, payload_json)
    nextion.sendnx(payload)
    tasmota.resp_cmnd_done()
end

tasmota.add_cmd('Nextion', send_cmd)

def send_cmd2(cmd, idx, payload, payload_json)
    nextion.send(payload)
    tasmota.resp_cmnd_done()
end

tasmota.add_cmd('Screen', send_cmd)
tasmota.add_cmd('NxPanel', send_cmd2)

tasmota.add_rule("power1#state", /-> nextion.set_power())
tasmota.add_rule("power2#state", /-> nextion.set_power())
tasmota.cmd("Rule3 1") # needed until Berry bug fixed
tasmota.add_rule("Time#Minute", /-> nextion.set_clock())
tasmota.add_rule("system#boot", /-> nextion.screeninit()) 

tasmota.cmd("State")

Voila le nspanel version US ( format vertical)

Comme tu peux le constater JMQTT fonctionne très bien : j’envoi les infos de température , je peux piloter l’allumage des lampes et j’ai bien le retour d’info des lampes allumées .
Je n’ai qu’une page d’utilisée actuellement mais on peu facilement faire du multi page par scrolling de page
( la photo est moins bien que l’original )

Bonjour, perso j’utilise pas mais j’ai souvenir avec une rom espeasy j’envoyais par jmqtt un lancement rules qui lui contient la mélodie buzzer. Ça évite les ligne interminable ! Tu n’as pas ça « rules : petit scénario » sur tasmota ?

Bonjour ,
Je sais que sous espeasy cela fonctionne effectivement avec les rules .
Je n’avais pas du tout pensé aux rules sous tasmota .
Lorsque je regarde tasmota il y a possibilité d’envoyer des rules pour un thermostat par exemple .

Souvent on oublie de regarder ce qu’on a devant les yeux , les rules permettent aussi d’interdire l’allumage des lampes du nspanel lorsqu’il fait jour …
En désespoir j’étais pret à intercaller un micro esp sur le buzzer avec esapesy pour la partie melodie .

Salut @nadlio
As-tu réussi à faire jouer des mélodies depuis Tasmota ?

Bonjour , non j’ai juste la fonction buzzer
Avec mon HA cela fonctionnait , mais comme je n’ai plus HA je n’ai pas continué mes recherches .
Et comme visiblement cette fonctionnalité n’interesse personne j’ai mis de coté .

C’est vrai que peu de monde n’a l’air d’utiliser le buzzer en rtttl/mélodie, mais n’en ayant pas moi-même, je suis tributaire de ce que tu m’envoies pour t’aider :

@dcat, si tu as des logs de ce qui est échangé entre HA et le NS Panel, il doit être possible de reproduire le fonctionnement sous Jeedom en envoyant la même chose sur le même topic avec le même firmware.

Bad

Hello,

Je me suis repenché sur ta question, suite au tuto de @dcat :

Pour info, Tasmota en version 12.5.0 inclurait le support du RTTTL. La release note n’y fait pas mention, et ce n’est pas vraiment documenté, mais le merge est antérieur à la libération de la version.

Exemple de command: I2SRtttl 1up:d=8,o=5,b=200:e6,g6,e7,c7,d7,g7

Enjoy.

Bad

Merci @Bad

Je suis en [Tasmota 12.5.0.2 ] et ça ne fonctionne pas :frowning:

Bonjour ,

de retour apres une petite absence …
@Bad merci pour ton retour sur cette fonctionnalité qui est effectivement disponible sous Tasmota car j’avais fait l’essai sous HA et 12.5.0 , mais je n’avais pas été plus loin car sous Jeedom impossible à faire fonctionner .

Donc pour la suite j’ai la fonction buzzer qui fonctionne soit avec le buzzer soit avec le PWM6 dans la configuration de Tasmota .
Je teste ton exemple de commande ça ne fonctionne pas , je met peut etre la mauvaise info .

Dans le topic initial de mon équipement j’ai :
cmnd/tasmota_EACCF4/PWM6
( tasmota_EASSF4 est le nom de mon équipement lors du flash que je n’ai pas changé )
pour la valeur je peux mettre :
de 0 à 100 = 0 pas de son et plus je vais vers 100 et plus c’est fort .

Donc j’ai essayer de remplacer la valeur par ton exemple : 1up:d=8,o=5,b=200:e6,g6,e7,c7,d7,g7
et la commande : cmnd/tasmota_EACCF4/I2SRtttl

Helo,

Peux-tu préciser et regarder exactement ce qui est envoyé par HA en RTTTL avec MQTT explorer ?

Si je résume :
Avec ESP Easy:
Payload rtttl,14,d=4,o=5,b=112:8a[...] sur esp/cmd → OK

Avec tasmota:
I2SRtttl 1up:d=8,o=5,b=200:e6,g6,e7,c7,d7,g7 sur cmnd/tasmota_EACCF4/I2SRtttl → KO
50 sur cmnd/tasmota_EACCF4/PWM6 → juste un BIP

Pour t’aider, j’ai vraiment besoin de savoir quel message ou quelle suite de messages est/sont envoyés par HA et sur quels topics pour faire le RTTTL.

Je pense qu’on est pas loin de quelque chose, mais à mon avis ce ne sera pas un message simple, car le code de Tasmota ne gère (selon moi) pas nativement le RTTTL quand il n’y a pas de « carte son » branchée en I2S sur l’ESP.

Bad

Bonjour ,
Pour HA ça va etre difficile de te donner l’info car je l’ai totalement abandonné ( je n’ai plus le système d’installé )
et oui pour : cmnd/tasmota_EACCF4/PWM6` → juste un BIP qui se règle en intensité de 0 à 100 %

Peux tu me dire où tu as trouvé la fonction I2SRtttl ?
Est elle dans les templates d’équipement dans tasmota ?

Carte son ? le Nspanel « diffuse » du son sous HA et Tasmota .
Je pense que HA " appel " la fonction rtttl qui est incluse dans tasmota

Ce Nspanel est quand meme une sacrée usine à gaz , :face_with_monocle:

Bonjour Bad ,

Après de nombreuse recherche et essai cela ne fonctionnait pas .
J’ai trouvé l’info pour I2SRttl , la fonction existe mais n’est pas compilé automatiquement dans le firmware Tasmota , il faut la compiler soit meme et l’ajouter dans le programmme .
(présent dans HA et Espeasy )
Ayant completement planté mon Nspanel à force de faire des essai j’ai décider de le passer sous ESP easy .
J’ai du rechercher quelque fonction mais tout fonctionne avec et les mélodie rtttl ausssi , c’est beaucoup plus simple .
Il suffit de mettre dans une action , défaut : par exemple
rtttl,21:d=4,o=5,b=100:16e6,16e6 et ça mélodie .
( 21 = gpio du buzzer ) chez moi

Merci à toi pour tes recherches .
Maintenant que je suis sous espeasy il va rejoindre ma longue série de modules .

Par exemple : (en cours de test )

1 « J'aime »