Follow me status - notify to Yealink BLF LED

Hi there!

I'm willing to pay someone that can create a feature that changes the BLF LED on Yealink phones depending on the Follow Me status on a user extension.
Much like the feature that's available for Call Center agent status here:
https://www.pbxforums.com/threads/agent-status-blf.549

My users needs to be able to change their status on the BLF key (*21?) and in the web-gui and the LED should be updated to reflect the current status.

Anyone up to the task? :)

Best regards!
 
There is a fair chance that much of the code you need already exists. Have a look at /etc/freeswitch/autoload_configs/lua.conf.xml In this file you will see some startup-scripts, probably commented out. Have a look at the reference to call_flow_monitor.lua and the call_flow_monitor.lua script itself in /usr/share/freeswitch/scripts.

I use this feature to drive BLFs to indicate night service.
 
Hi again,
I've tried to get the Follow Me LED working and I'm almost there.
The only thing that's not working right now is the Notify from the pbx to the phone, it always contains <state>confirmed</state> meaning the lamp will get activated no matter if I'm enabling or disabling the feature.
For reference when using the call-center login/logout hotkey, the Notify packet contains <state>confirmed</state> or <state>terminated</state> depending if I'm logging in or logging out.

The Subscribe-request works perfectly.

So here's what I've done so far:
Dialplan: (Working as intended)
Capture.PNG

blf_subscribe.lua: (Working as intended)
Code:
local find_fm do

local find_fm_sql = [[select t2.follow_me_enabled
from v_extensions t1 inner join v_follow_me t2 on t1.follow_me_uuid = t2.follow_me_uuid
inner join v_domains t3 on t1.domain_uuid = t3.domain_uuid
where t3.domain_name = :domain_name and (t1.extension = :extension or t1.number_alias = :extension)
]]

find_fm = function(user)
    local ext, domain_name = split_first(user, '@', true)
    if not domain_name then return end
    local dbh = Database.new('system')
    if not dbh then return end
    local fm = dbh:first_value(find_fm_sql, {domain_name = domain_name, extension = ext})
    dbh:release()
    return fm

end

end
Code:
protocols.fm = function(event)
    local from, to = event:getHeader('from'), event:getHeader('to')
    local expires = tonumber(event:getHeader('expires'))
    if expires and expires > 0 then
        local proto, user = split_first(to, '+', true)
        user = user or proto
        local fm_status = find_fm(user)
        if fm_status then
            log.noticef("Find Follow Me: %s status: %s", to, tostring(fm_status))
            presence_in.turn_lamp(fm_status == "true", to)
        else
            log.warningf("Can not find Follow Me: %s", to)
        end
    else
        log.noticef("%s UNSUBSCRIBE from %s", from, to)
    end
end
follow_me.lua: (Notify is being sent but the contents of tag <state> is always "confirmed", no matter what.)
Code:
local presence_in = require "resources.functions.presence_in"
Code:
--trigger BLF led status change
    if (enabled == "false") then
        blf_status = "false"
    end

    if string.find(extension, 'fm+', nil, true) ~= 1 then
        presence_in.turn_lamp( blf_status,
            'fm+'..extension.."@"..domain_name
        );
    end
Here's an example of the SIP Notify contents that's being sent to the phone:

Code:
Subscription-State: active;expires=811
Content-Type: application/dialog-info+xml
Content-Length: 268

<?xml version="1.0"?>
<dialog-info xmlns="urn:ietf:params:xml:ns:dialog-info" version="113" state="full" entity="sip:fm+8426@domain">
<dialog id="7bcee63c-fad5-4d47-92b6-9c41bdcf2019" direction="recipient">
<state>confirmed</state>
</dialog>
</dialog-info>
 
Hi @KonradSC

Thanks for your response and sorry for my late reply..
I tried to include and modify the event-section from agent_status to follow_me.lua but I never got it to make any difference so I removed it again.
I may have failed in setting it up correctly...

The interesting thing is that the event is registered (according to below debug-output) even without the event-section in follow_me.lua:

From freeswitch log: (hostname, IP and domain have been removed)
Code:
019-05-15 09:02:37.988452 [DEBUG] switch_cpp.cpp:1443 [presence] turn_lamp: fm+8426@DOMAIN - false(string)
2019-05-15 09:02:37.988452 [DEBUG] switch_cpp.cpp:1443 [presence] Event-Name: PRESENCE_IN
Core-UUID: 0f0ce4e6-b7ad-4d33-b442-a0dd4a218889
FreeSWITCH-Hostname: HOSTNAME
FreeSWITCH-Switchname: HOSTNAME
FreeSWITCH-IPv4: IP
FreeSWITCH-IPv6: %3A%3A1
Event-Date-Local: 2019-05-15%2009%3A02%3A37
Event-Date-GMT: Wed,%2015%20May%202019%2007%3A02%3A37%20GMT
Event-Date-Timestamp: 1557903757988452
Event-Calling-File: switch_cpp.cpp
Event-Calling-Function: Event
Event-Calling-Line-Number: 314
Event-Sequence: 97819
proto: fm
event_type: presence
alt_event_type: dialog
Presence-Call-Direction: outbound
from: 8426%40DOMAIN
login: 8426%40DOMAIN
unique-id: 4b4fc109-abdd-4e92-922a-1ff2c836c1d0
status: Active%20(1%20waiting)
answer-state: confirmed
rpid: unknown
event_count: 1
Code:
2019-05-15 09:02:45.328456 [DEBUG] switch_cpp.cpp:1443 [presence] turn_lamp: fm+8426@DOMAIN - nil(nil)
2019-05-15 09:02:45.328456 [DEBUG] switch_cpp.cpp:1443 [presence] Event-Name: PRESENCE_IN
Core-UUID: 0f0ce4e6-b7ad-4d33-b442-a0dd4a218889
FreeSWITCH-Hostname: HOSTNAME
FreeSWITCH-Switchname: HOSTNAME
FreeSWITCH-IPv4: IP
FreeSWITCH-IPv6: %3A%3A1
Event-Date-Local: 2019-05-15%2009%3A02%3A45
Event-Date-GMT: Wed,%2015%20May%202019%2007%3A02%3A45%20GMT
Event-Date-Timestamp: 1557903765328456
Event-Calling-File: switch_cpp.cpp
Event-Calling-Function: Event
Event-Calling-Line-Number: 314
Event-Sequence: 97909
proto: fm
event_type: presence
alt_event_type: dialog
Presence-Call-Direction: outbound
from: 8426%40DOMAIN
login: 8426%40DOMAIN
unique-id: 446ea29b-4307-4a1d-8c8f-a95ce76375f8
status: Active%20(1%20waiting)
answer-state: terminated
To me this looks correct when compared to the output of the agent_status feature, "only" thing that's not correct is the content of the notify-packets when using the follow_me lua.