Utilisation de melodie de type rtttl

Bonjour ,
J’utilise le pluging Jmqtt pour communiquer avec mon nspanel Sonoff avec firmware modifié sous Tasmota
Les commandes marche dans les 2 sens pas soucis pour l’envoi ou le retour d’info .
La fonction buzzer qui est disponible sous Tasmota , est sous la forme de chiffres :
par exemple pour le topic : cmnd/nspanel_7D2DD8/BUZZER avec une valeur 2 2 2 2 =
2 bips avec 2 intervalles vide donc ça fonctionne .
Il existe sous Home Assistant des programme pour le nspanel sous forme de fichier yaml avec la fonction rtttl qui envoi des séquences .
Par exemple :

Paylod rtttl,14,d=4,o=5,b=112:8a,8a,a,8a,8a,a,8a,8c6,8f.,16g,2a,8a#,8a#,8a#.,16a#,8a#,8a,8a.,16a,8a,8g,8g,8a,g,c6 

ce qui envoi une mélodie au buzzer du nspanel (c’est beaucoup mieux que de simple bip parce ce qu’il existe plein de mélodie disponible )

Donc ma question qu’elle est la syntaxe que je dois mettre dans valeur du pluging et rtttl ou doit il etre intégré ? faut il modifier le fichier dans la console tasmota de l’équipement ?
Je n’arrive pas à trouver comment transposer rtttl d’un fichier yaml pour avoir l’équivalent vers jmqtt .

Sous Espeasy c’est encore plus simple par exemple:

http://IP/control?cmd=rtttl,14:d=4,o=5,b=112:8a,8a,a,8a,8a,a,8a,8c6 = 

envoi d’une mélodie

Hello,

Il n’y a rien de tel intégré de base dans jMQTT (et je ne crois pas que ça existe non plus dans Jeedom en général).

Par contre, vu que HA va certainement envoyer les rtttl en mqtt, il te suffit de les jouer avec HA et d’écouter le résultat sur le topic de destination avec MQTT Explorer (ou autre) et de rejouer le même payload avec jMQTT.

Qu’en dis-tu ?

Bad

Bonjour ,
@Bad merci pour ton retour ,
je voulais pouvoir utiliser cette solution sans avoir besoin de HA ou de Espeasy par exemple .
J’ai HA sur Raspberry mais qui me sert uniquement pour tester des applications qui ne sont pas sur Jeedom .
Ma domotique est gérée par Jeedom .
Donc si je comprend bien la ’ fonction ’ rtttl est intégrée de base dans HA ou Espeasy ce qui n’est pas le cas dans Jeedom .
Est il possible de l’intégrer ?

Je suis surpris que rtttl ne soit pas quelque chose de courant , c’est beaucoup mieux de pouvoir programmer différente mélodie suivant les états , que de simple bip …sachant que le matériel physique est capable de le faire .

Hello,

Je ne pense pas qu’on se soit bien compris, je te propose juste d’utiliser HA pour envoyer un ordre au buzzer de ton NS Panel et de regarder ce qu’il envoie avec MQTT Explorer pour comprendre ce qu’il faut que tu envoies depuis jMQTT.

Il y a de fortes changes pour qu’il envoie simplement rtttl,14:d=4,o=5,b=112:8a,8a,a,8a,8a,a,8a,8c6 sur le topic cmnd/nspanel_7D2DD8/BUZZER, dans ce cas tu peux reprendre ca dans jMQTT et l’affaire est jouée.

Par contre, si HA envoie une suite de messages mqtt, alors ça ne va pas être possible via jMQTT, car jMQTT est simplement une interface entre Jeedom et MQTT, pas entre NS Panel et Jeedom.

Bad

ok , j’avais pas bien compris .
Je vais tester ton idée.

Bonjour @nadlio,

J’ai vu ton nouveau sujet, avant de monter une usine à gaz entre mqtt, ha et Jeedom pour piloter le buzzer de ton nspanel, peux tu me dire ce que Mqtt explorer vois en mqtt quand tu envoies un rtttl depuis ha ?

Bonjour Bad ,
le retour mqtt est sous la forme 'MissionImp:d=16,o=6,b=95:32d,32d#,32d,32d#,32d,32d#,32d,32d#,32d,32d,32d#,32e,32f,32f#,32g,g,8p,g,8p,a#,p,c7,p,g,8p,g,8p,f,p,f#,p,g,8p,g,8p,a#,p,c7,p,g,8p,g,8p,f,p,f#,p,a#,g,2d,32p,a#,g,2c#,32p,a#,g,2c,a#5,8c,2p,32p,a#5,g5,2f#,32p,a#5,g5,2f,32p,a#5,g5,2e,d#,8d'

par exemple pour mission impossible , ( c’est juste un test )

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é .