AntoineGS / teams-status-rs

47 stars 0 forks source link

Additional status sensor #7

Open aregart opened 6 months ago

aregart commented 6 months ago

It would be great to have an additional sensor in HA that reflects the actual user status. The "Away", "Busy", "Available" etc statuses I mean. Is that possible?

AntoineGS commented 6 months ago

Unfortunately not, the Teams API does not have this data. You can see the data available here. I have not checked how verbose the logs are recently but it was also not available by parsing the logs a couple of months back (which is another approach altogether). If the logs now log that information I would be investigate this further.

AntoineGS commented 5 months ago

Good news I just saw that the logs have the status, they are now in: C:\Users\<youruser>\AppData\Local\Packages\MSTeams_8wekyb3d8bbwe\LocalCache\Microsoft\MSTeams\Logs\ The ones matching MSTeams_*.log I will see what I can do for this.

AntoineGS commented 5 months ago

Closed the wrong issue, my bad

itchensen commented 5 months ago

Already played with the log-files you identified as well prior to finding your new version. Got that log-thing part up-and-running for indicating status, meeting, webcam etc, BUT, and that was the reason for further investigating and finding your new solution, this was quite unstable. The reason for that ist, that the log-files rotate in an irregular time / intvervall, which let the log-crawler regularly crash and therefore unavailable sensors in HA.

That was my adopted piece of code:

# Configuring parameter for interactive run
Param($SetStatus)

# Import Settings PowerShell script
. ($PSScriptRoot + "\TSFunctions.ps1")
. ($PSScriptRoot + "\Settings.ps1")
$locLang = GetFirstNonEmpty -firstString $env:TSLANG -secondString "en"
. ($PSScriptRoot + "\Lang-$locLang.ps1")

# Some variables
$HAToken = $env:TSHATOKEN
$HAUrl = $env:TSHAURL
$appDataFolder = GetAppDataFolder
#$logFolder = "$appDataFolder\Local\Packages\MSTeams_8wekyb3d8bbwe\LocalCache\Microsoft\MSTeams\Logs"
$logFolder = "C:\Users\tgroene\AppData\Local\Packages\MSTeams_8wekyb3d8bbwe\LocalCache\Microsoft\MSTeams\Logs"
$logFile = Get-ChildItem -Path $logFolder -Filter "MSTeams_*.log" | Sort-Object LastAccessTime -Descending | Select-Object -First 1
$userName = GetUserName

$teamsStatusHash = @{
    # Teams short name = @{Teams long name = HA display name}
    # Can be set manually in Teams
    "Available" = @{"Available" = $tsAvailable}
    "Busy" = @{"Busy" = $tsBusy}
    "Away" = @{"Away" = $tsAway}
    "BeRightBack" = @{"BeRightBack" = $tsBeRightBack}
    "DoNotDisturb" = @{"DoNotDisturb" = $tsDoNotDisturb}
    "Offline" = @{"Offline" = $tsOffline}
    # Automated statuses
    "Focusing" = @{"Focusing" = $tsFocusing}
    "Presenting" = @{"Presenting" = $tsPresenting}
    "presentertoolbar" = @{"Presenting" = $tsPresenting}
    "InAMeeting" = @{"InAMeeting" = $tsInAMeeting}
    "OnThePhone" = @{"OnThePhone" = $tsOnThePhone}
}

# Ensure these are initialized to null so the first hit triggers an update in HA
$currentStatus = $null
$currentActivity = $null
$currentCamStatus = $null

# Some defaults
$camStatus = $csCameraOff
$camIcon = "mdi:camera-off"
$defaultIcon = "mdi:microsoft-teams"

# Run the script when a parameter is used and stop when done
If($null -ne $SetStatus){
    InvokeHA -state $SetStatus -friendlyName $entityStatusName -icon $defaultIcon -entityId $entityStatusId
    break
}

Write-Host "Used Log Files: $logFile"

# Start monitoring the Teams logfile when no parameter is used to run the script
#Get-Content -Path "$appDataFolder\Microsoft\Teams\logs.txt" -Encoding Utf8 -Tail 1000 -ReadCount 0 -Wait | % {
Get-Content -Path $logFile.fullName -Encoding Utf8 -Tail 1000 -ReadCount 0 -Wait | % {
    # Get Teams Logfile and last icon overlay status
    $TeamsStatus = $_ | Select-String -Pattern `
        'Received Action: UserPresenceAction:',`
        'Navigation starting: about:blank?entityType=presentertoolbar'      | Select-Object -Last 1

    # Get Teams Logfile and last app update deamon status
    $TeamsActivity = $_ | Select-String -Pattern `
        'WebClientStatesModule',`
        'Attempting to play audio for notification type 1' | Select-Object -Last 1

    # Get Teams application process
    $TeamsProcess = Get-Process -Name *Teams* -ErrorAction SilentlyContinue

    # Check if Teams is running and start monitoring the log if it is
    If ($null -ne $TeamsProcess) {
        If($null -ne $TeamsActivity){
            If ($TeamsActivity -like "*new_state=Active*" -or `
                    $TeamsActivity -like "*new_state=Inactive*" -or `
                    $TeamsActivity -like "*new_state=LongInactive*") {
                $Activity = $taNotInACall
                $ActivityIcon = $iconNotInACall
                If ($currentStatus -eq $tsPresenting) {
                    $Status = $tsDoNotDisturb
                } ElseIf ($currentStatus -eq $tsInAMeeting) {
                    $Status = $tsBusy   
                }
            }
            ElseIf ($TeamsActivity -like "*new_state=VeryActive*") {
                $Activity = $taInACall
                $ActivityIcon = $iconInACall
            }
            ElseIf ($TeamsActivity -like "*Attempting to play audio for notification type 1*") {
                $Activity = $taIncomingCall
                $ActivityIcon = $iconInACall
            }
        }

        If($null -ne $TeamsStatus) {
            $teamsStatusHash.GetEnumerator() | ForEach-Object {
                If ($TeamsStatus -like "*, availability: $($_.value.keys[0])}" -or `
                    $TeamsStatus -like "*Navigation starting: about:blank?entityType=$($_.key)*") {
                    $Status = $($_.value.values[0])
                    If ($Activity -eq $taInACall -And $Status -eq $tsDoNotDisturb) {
                        $Status = $tsPresenting
                    } ElseIf ($Activity -eq $taInACall) {
                        $Status = $tsInAMeeting 
                    }
                }
            }
        }
    }
    # Set status to Offline when the Teams application is not running
    Else {
        $Status = $tsOffline
        $Activity = $taNotInACall
        $ActivityIcon = $iconNotInACall
    }

    If($null -ne $TeamsStatus) {
        Write-Host "Teams Orig-Status: $TeamsStatus"
        Write-Host "Teams Status: $Status"
    }

    If($null -ne $TeamsActivity) {
        Write-Host "Teams Orig-Activity: $TeamsActivity"
        Write-Host "Teams Activity: $Activity"
    }

    # Webcam support (sensor.teams_cam_status)
    # While in a call, we poke the registry for cam status (maybe too often), but I could not find a log entry to use as a trigger 
      # to know when to check the camera status so it might be hit or miss. 
      # When leaving a call it maybe not trigger as something non-camera related needs to get logged to trigger the check.
    If($Activity -eq $taInACall -or $camStatus -eq $csCameraOn) {
        $registryPath = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam\MSTeams_8wekyb3d8bbwe\"

        $webcam = Get-ItemProperty -Path $registryPath -Name LastUsedTimeStop | select LastUsedTimeStop

        If ($webcam.LastUsedTimeStop -eq 0) {
            $camStatus = $csCameraOn
            $camIcon = "mdi:camera"
        }
        Else {
            $camStatus = $csCameraOff
            $camIcon = "mdi:camera-off"
        }
    }

    # Call Home Assistant API to set the status and activity sensors
    If ($currentStatus -ne $Status -and $Status -ne $null) {
        $currentStatus = $Status
        InvokeHA -state $currentStatus -friendlyName $entityStatusName -icon $defaultIcon -entityId $entityStatusId
    }

    If ($currentActivity -ne $Activity) {
        $currentActivity = $Activity
        InvokeHA -state $Activity -friendlyName $entityActivityName -icon $ActivityIcon -entityId $entityActivityId
    }

    If ($null -ne $camStatus -and $currentCamStatus -ne $camStatus) {
        $currentCamStatus = $camStatus
        InvokeHA -state $camStatus -friendlyName $entityCamStatusName -icon $camIcon -entityId $entityCamStatusId
    }
}
AntoineGS commented 5 months ago

Thanks for the info, I have started work on this but as you mentioned log files are being rotated so I am taking time ensuring rotations will be detected as quickly as possible (I am currently attempting with the notify crate). Once that's stable I will work on the parsing of the file, at which point what you posted will be quite helpful!

pvmil commented 3 months ago

a small remark: I was using the powershell as also described here . That does require admin rights, I do not have these (and expect this move for more people/companies), it would (at least for me) be nice if this is also not required in the future.

(I installed this solution today, thanks a lot!! I'm really happy!)

AntoineGS commented 2 months ago

I don't plan on having admin rights required for this! I did run into an issue with the log parsing, it seems there is no log entry when manually changing the status back to 'Available' so for the time being there is no point in continuing the integration with the log file :(

kmcbride3 commented 1 month ago

It seems that around April 29, they added logging for status changes; I an example from my logs (user id scrubbed). For each change in status, at least when I manually set (or reset) my status, all three entries below are captured in the log.

2024-04-30T16:29:56.670497-04:00 0x000100c8 <INFO> native modules::UserDataCrossCloudModule: Received Action:  UserPresenceAction: {cloud_context: https://teams.microsoft.com , user id: 000a00aa-0000-0a00-a000-a0aa00000a0a, availability: Available}
2024-04-30T16:29:56.672498-04:00 0x000100c8 <INFO> native modules::UserDataCrossCloudModule: CloudStateChanged: New Cloud State Event: UserDataCloudState total number of users: 1 { user id : 000a00aa-0000-0a00-a000-a0aa00000a0a, availability: Available, unread notification count: 2 }
2024-04-30T16:29:56.673497-04:00 0x000100c8 <INFO> native_modules::UserDataCrossCloudModule: BroadcastGlobalState: New Global State Event: UserDataGlobalState total number of users: 1 { user id  : 000a00aa-0000-0a00-a000-a0aa00000a0a, availability: Available, unread notification count: 2 } 
PablaV commented 1 month ago

Now that statuses are logged is this something that can be included? I desperately miss being able to see my teams status through HA

AntoineGS commented 1 month ago

It should, though I have been busy with a ton of other projects these days so I have not looked into it yet. I'll see what I can do.

AntoineGS commented 1 month ago

Ok so I encountered some new issues:

PablaV commented 1 month ago

Ugh that's a shame! Hopefully a solution can be figured out one day

kmcbride3 commented 1 month ago

Just stumbled across this https://learn.microsoft.com/en-us/microsoftteams/log-files#end-user-configuration

I will test whether enabling it creates a continuous stream.