fermax-blue-intercom icon indicating copy to clipboard operation
fermax-blue-intercom copied to clipboard

Propositions for enchancements

Open yawor opened this issue 2 years ago • 17 comments

Hi,

The script works great, but there's a lot of space for making it better.

Right now it can't be used as a library in other software, for example as a library used by HA integration. This is because all code is executed as soon as the file is imported. For this to work as a library, the main logic should also be inside a function and it should be called in a guarding condition like this:

if __name__ == "__main__":
    main()

if the main logic is in the main() function.

For this to work great as a library (especially if used in the HA integration) the requests library should be replaced by some async http library like aiohttp or httpx. HA already uses httpx and has it installed, so I'd opt for using this one also.

RIght now the script doesn't use refresh token, which is actually really helpful. I'd change whole authentication part of the script. First of all I'd separate authentication from opening the doors. The user would first use auth command. Providing username and password in the command line could left as an option, but I'd use prompts if either one or both of them is not provided. So user would just call auth and the script would first as for username and then for password (in safe way, hiding the input). The auth would then save both access token and refresh token, together with max age (expiry timestamp could also be calculated right away ans stored). The door opening would not accept username and password anymore. Instead it would need to check if the access token is almost expired (for example if it expires in 2 days or less, which is half of the max age for the token) - if yes, then before opening the doors, it would use refresh_token to refresh access token by POSTing grant_type=refresh_token&refresh_token=<current_refresh_token> to /oauth/token. This is a correct way of using OAuth2 and I've tested it using curl and this works correctly on Fermax server. There could also be a command to only check if access token expires shortly and refresh it if it's needed - this could be run from crontab to always keep the access token fresh.

The last thing is to properly package this script as a library. I propose using Poetry as a packaging tool.

yawor avatar Jun 09 '23 16:06 yawor

Hi @yawor, thank you very much for your feedback, I really appreciate it!, every single thing you've pointed out it's quite interesting, and I completely agree, sadly I don't have much free time to maintain this script 😢. If you are interested in contributing to the project with any small improvement it would be awesome.

marcosav avatar Jun 09 '23 18:06 marcosav

I know that's a lot of work and I'm fully prepared to work on these points. To be honest, I've already started :).

yawor avatar Jun 09 '23 18:06 yawor

BTW @marcosav, would you be able to share the original HTTP traffic you've captured from the Blue app (of course with your credentials or deviceId stripped)? Right now, when calling directed-opendoor endpoint to open the door the server returns a message in Spanish. When I open the door from the Blue app, I get a message in Polish that the door is opened. I also get appropriate message when I try to open a door that doesn't exist. I think that the message displayed in the app is actually sent by the server and not embedded in the app itself. I've decompiled the Blue app and there are no such messages there. This means it's possible that the server can return localized messages instead only in Spanish. I've tried sending Accept-Language header set to pl_PL, but I still get a message in Spanish. Maybe there is some other parameter passed from the app to the server.

For some reason I can't capture any traffic from the Blue app using mitmproxy. The app probably uses certificate pinning, which causes it not to accept mitmproxy generated certificate (I've had mitmproxy CA certificate installed as trusted during the tests).

yawor avatar Jun 09 '23 18:06 yawor

Of course!

As soon as I open the Blue app the following executes:

  • GET https://blue.fermax.com/user/api/v1/users/me Response:
{
  "email": "[email protected]",
  "locale": "EN",
  "acceptSharing": false,
  "acceptPrivacy": true,
  "enabled": true,
  "createdAt": "2023-03-25T10:19:24.063+00:00",
  "country": "es",
  "city": "City",
  "area": "Norte",
  "zone": "Portugal and Spain",
  "subzone": "Spain",
  "pin": null,
  "pinDate": null,
  "uniqueSession": false,
  "provider": null,
  "name": null
}
  • GET https://blue.fermax.com/pairing/api/v3/pairings/me Response:
[
  {
    "id": "A UUID",
    "deviceId": "MyDeviceID",
    "tag": "Portal",
    "status": "PAIRED",
    "updatedAt": 1679740105258,
    "createdAt": 1679740067990,
    "appBuild": 599,
    "appVersion": "3.2.1",
    "phoneModel": "MyAndroidPhoneModel",
    "phoneOS": "MyAndroidPhoneOS",
    "home": null,
    "address": null,
    "accessDoorMap": {
      "ZERO": {
        "title": "",
        "accessId": {
          "block": 200,
          "subblock": -1,
          "number": 0
        },
        "visible": true
      },
      "ONE": {
        "title": "",
        "accessId": {
          "block": 200,
          "subblock": -1,
          "number": 1
        },
        "visible": false
      },
      "GENERAL": {
        "title": "",
        "accessId": {
          "block": 100,
          "subblock": -1,
          "number": 0
        },
        "visible": false
      }
    },
    "master": true
  }
]
  • GET https://blue.fermax.com/deviceaction/api/v1/device/MyDeviceID Response:
{
  "deviceId": "MyDeviceID",
  "connectionState": "Connected",
  "status": "ACTIVATED",
  "primaryThumbprint": null,
  "installationId": "",
  "family": "MONITOR",
  "type": "VEO-XS",
  "subtype": "WIFI",
  "numBlock": 0,
  "numSubblock": 0,
  "unitNumber": 2,
  "connectable": true,
  "iccid": "",
  "divertService": "blueStream",
  "photocaller": true,
  "wirelessSignal": 4,
  "blueStream": true,
  "phone": false,
  "panelOrEdibox": false,
  "monitor": true,
  "terminal": true
}
  • GET https://blue.fermax.com/services2/api/v1/services/MyDeviceID Response:
[
  "AccessName",
  "AutoOn",
  "CallDivert",
  "CallRegistry",
  "ChangeVideoSource",
  "CheckInformation",
  "DND",
  "Doormatic",
  "EventRegistry",
  "F1",
  "F1Options",
  "Geo",
  "Guard",
  "Guest5",
  "ManageCallDivert",
  "OpenDoor",
  "Photocaller",
  "Ringtone",
  "SessionsUnlimited",
  "TZ"
]
  • (Same request repeats)
  • GET https://blue.fermax.com/deviceaction/api/v1/device/MyDeviceID (Same as before)
  • GET https://blue.fermax.com/services2/api/v1/services/MyDeviceID (Same as before)
  • POST https://blue.fermax.com/deviceaction/api/v1/device/MyDeviceID/directed-opendoor Body:
{
  "number": 0,
  "block": 200,
  "subblock": -1
}

Response:

la puerta abierta

Also, this may be useful, when I press the video button:

  • POST https://blue.fermax.com/deviceaction/api/v2/device/MyDeviceID/autoon Body:
{
  "directedToBluestream": "MyAppToken",
  "deviceID": "MyDeviceID"
}

Response:

{
  "reason": "call_starting",
  "divertService": "blueStream",
  "code": 1,
  "additional_info": {
    "technology": "duox",
    "remote": {
      "number": 0,
      "address": "00 F0 A0",
      "block": 0,
      "type": "panel",
      "subblock": -1
    },
    "local": {
      "number": 2,
      "address": "00 00 02",
      "subtype": "monitor",
      "block": 0,
      "type": "terminal",
      "subblock": 0
    }
  },
  "description": "Auto on is starting",
  "directedTo": "MyAppToken"
}
  • POST https://blue.fermax.com/callManager/api/v1/message/ack?attended=1&fcmMessageId=1686495975891207 Response:
{
  "timestamp": "2023-06-11T15:35:40.368+00:00",
  "status": 400,
  "error": "Bad Request",
  "path": "/api/v1/message/ack"
}
  • POST https://oauth.blue.fermax.com/oauth/token?grant_type=refresh_token&refresh_token=MyResfreshToken Response: Auth response
  • GET https://calldivertsignserver01-pro-west-europe.blue.fermax.com/socket.io/?transport=polling&b64=1 (or calldivertsignserver02-pro-west-europe) Response:
119:0{"sid":"A20characterAlphanumericId","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":100000,"maxPayload":1000000}
  • GET https://calldivertsignserver01-pro-west-europe.blue.fermax.com/socket.io/?transport=polling&b64=1&sid=ThePreviousID Response:
2:40
  • POST https://calldivertsignserver01-pro-west-europe.blue.fermax.com/socket.io/?transport=polling&b64=1&sid=ThePreviousID Body:
1:2

Response:

ok
  • GET https://calldivertsignserver01-pro-west-europe.blue.fermax.com/socket.io/?transport=polling&b64=1&sid=ThePreviousID Response:
1:3
  • GET https://calldivertsignserver01-pro-west-europe.blue.fermax.com/socket.io/?transport=polling&b64=1&sid=ThePreviousID Response:
7465:430[{"result":{"iceServers":[{"credential":"pulpoconcachelos","credentialType":"password","urls":["turn:coturn-pro-west-europe.westeurope.cloudapp.azure.com:443?transport=tcp"],"username":"fermaxturn"}],"producerIdVideo":"487884e7-1615-40c0-9b93-205dd7822f8c","producerIdAudio":"ab570315-8619-41b4-9a1c-ac2ab9fd781a","recvTransportVideo":{"id":"eee97d17-b6db-4be7-ab0b-dd69cdaa141e","dtlsParameters":{"fingerprints":[{"algorithm":"sha-256","value":"2F:0C:C1:1F:5C:90:A4:36:FC:61:27:DF:8B:44:D8:33:47:9E:D1:FC:17:3A:E6:BA:34:E9:CE:53:C2:E4:D1:EA"},{"algorithm":"sha-384","value":"67:10:D2:45:2A:57:AC:06:7A:5F:B7:2D:7B:FD:0A:E3:9D:C5:D2:54:58:A0:6D:B9:31:A9:56:CC:5E:CC:CF:2C:97:CF:D9:1A:1F:5C:12:B2:6F:49:B2:14:8F:14:45:22"},{"algorithm":"sha-1","value":"38:FE:94:EB:D1:12:87:D0:58:58:72:21:0E:AE:93:E4:AA:27:6C:1E"},{"algorithm":"sha-512","value":"BF:CF:47:B6:AF:9E:C5:F1:33:4C:97:98:DD:D3:94:F6:E4:A9:1A:2D:45:87:BD:08:06:68:D6:A6:94:4F:E0:13:B5:FE:E3:23:06:3E:89:99:52:45:24:69:93:DD:8A:77:C6:B7:BC:6F:92:D7:72:13:66:F2:7C:05:DB:DF:41:73"},{"algorithm":"sha-224","value":"95:B0:25:D3:11:9A:96:C0:EC:80:51:C6:E6:21:55:47:8B:EE:92:F9:B4:62:14:48:A0:44:49:62"}],"role":"auto"},"iceCandidates":[{"foundation":"udpcandidate","ip":"20.126.206.57","port":58759,"priority":1076302079,"protocol":"udp","type":"host"},{"foundation":"udpcandidate","ip":"2603:1020:201:10::52","port":41034,"priority":1076276479,"protocol":"udp","type":"host"}],"iceParameters":{"iceLite":true,"password":"64d71r2bohos0318bdaoi4rcxmd9pged","usernameFragment":"4ubxz5g9u7aee5f6tzoygixe74jn32gv"}},"routerRtpCapabilities":{"codecs":[{"kind":"audio","mimeType":"audio/PCMA","preferredPayloadType":8,"clockRate":8000,"rtcpFeedback":[{"type":"transport-cc","parameter":""}],"channels":1,"parameters":{}},{"kind":"video","mimeType":"video/H264","clockRate":90000,"parameters":{"level-asymmetry-allowed":1,"packetization-mode":1,"profile-level-id":"4d0032","x-google-start-bitrate":1000},"rtcpFeedback":[{"type":"nack","parameter":""},{"type":"nack","parameter":"pli"},{"type":"ccm","parameter":"fir"},{"type":"goog-remb","parameter":""},{"type":"transport-cc","parameter":""}],"preferredPayloadType":100},{"kind":"video","mimeType":"video/rtx","preferredPayloadType":101,"clockRate":90000,"parameters":{"apt":100},"rtcpFeedback":[]},{"kind":"video","mimeType":"video/H264","clockRate":90000,"parameters":{"level-asymmetry-allowed":1,"packetization-mode":1,"profile-level-id":"42e01f","x-google-start-bitrate":1000},"rtcpFeedback":[{"type":"nack","parameter":""},{"type":"nack","parameter":"pli"},{"type":"ccm","parameter":"fir"},{"type":"goog-remb","parameter":""},{"type":"transport-cc","parameter":""}],"preferredPayloadType":102},{"kind":"video","mimeType":"video/rtx","preferredPayloadType":103,"clockRate":90000,"parameters":{"apt":102},"rtcpFeedback":[]}],"headerExtensions":[{"kind":"audio","uri":"urn:ietf:params:rtp-hdrext:sdes:mid","preferredId":1,"preferredEncrypt":false,"direction":"sendrecv"},{"kind":"video","uri":"urn:ietf:params:rtp-hdrext:sdes:mid","preferredId":1,"preferredEncrypt":false,"direction":"sendrecv"},{"kind":"video","uri":"urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id","preferredId":2,"preferredEncrypt":false,"direction":"recvonly"},{"kind":"video","uri":"urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id","preferredId":3,"preferredEncrypt":false,"direction":"recvonly"},{"kind":"audio","uri":"http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time","preferredId":4,"preferredEncrypt":false,"direction":"sendrecv"},{"kind":"video","uri":"http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time","preferredId":4,"preferredEncrypt":false,"direction":"sendrecv"},{"kind":"audio","uri":"http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01","preferredId":5,"preferredEncrypt":false,"direction":"recvonly"},{"kind":"video","uri":"http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01","preferredId":5,"preferredEncrypt":false,"direction":"sendrecv"},{"kind":"video","uri":"http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07","preferredId":6,"preferredEncrypt":false,"direction":"sendrecv"},{"kind":"video","uri":"urn:ietf:params:rtp-hdrext:framemarking","preferredId":7,"preferredEncrypt":false,"direction":"sendrecv"},{"kind":"audio","uri":"urn:ietf:params:rtp-hdrext:ssrc-audio-level","preferredId":10,"preferredEncrypt":false,"direction":"sendrecv"},{"kind":"video","uri":"urn:3gpp:video-orientation","preferredId":11,"preferredEncrypt":false,"direction":"sendrecv"},{"kind":"video","uri":"urn:ietf:params:rtp-hdrext:toffset","preferredId":12,"preferredEncrypt":false,"direction":"sendrecv"},{"kind":"video","uri":"http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time","preferredId":13,"preferredEncrypt":false,"direction":"sendrecv"},{"kind":"audio","uri":"http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time","preferredId":13,"preferredEncrypt":false,"direction":"sendrecv"}]},"sendTransport":{"id":"e7af7ab4-d226-4a46-8e72-83f25618e911","dtlsParameters":{"fingerprints":[{"algorithm":"sha-256","value":"2F:0C:C1:1F:5C:90:A4:36:FC:61:27:DF:8B:44:D8:33:47:9E:D1:FC:17:3A:E6:BA:34:E9:CE:53:C2:E4:D1:EA"},{"algorithm":"sha-384","value":"67:10:D2:45:2A:57:AC:06:7A:5F:B7:2D:7B:FD:0A:E3:9D:C5:D2:54:58:A0:6D:B9:31:A9:56:CC:5E:CC:CF:2C:97:CF:D9:1A:1F:5C:12:B2:6F:49:B2:14:8F:14:45:22"},{"algorithm":"sha-1","value":"38:FE:94:EB:D1:12:87:D0:58:58:72:21:0E:AE:93:E4:AA:27:6C:1E"},{"algorithm":"sha-512","value":"BF:CF:47:B6:AF:9E:C5:F1:33:4C:97:98:DD:D3:94:F6:E4:A9:1A:2D:45:87:BD:08:06:68:D6:A6:94:4F:E0:13:B5:FE:E3:23:06:3E:89:99:52:45:24:69:93:DD:8A:77:C6:B7:BC:6F:92:D7:72:13:66:F2:7C:05:DB:DF:41:73"},{"algorithm":"sha-224","value":"95:B0:25:D3:11:9A:96:C0:EC:80:51:C6:E6:21:55:47:8B:EE:92:F9:B4:62:14:48:A0:44:49:62"}],"role":"auto"},"iceCandidates":[{"foundation":"udpcandidate","ip":"20.126.206.57","port":48517,"priority":1076302079,"protocol":"udp","type":"host"},{"foundation":"udpcandidate","ip":"2603:1020:201:10::52","port":31679,"priority":1076276479,"protocol":"udp","type":"host"}],"iceParameters":{"iceLite":true,"password":"1z13ibcx888z5ovx242sf4xq5xdgup8y","usernameFragment":"fhjpkd6rmqa1zylrwe4yl67gnznegnys"}},"recvTransportAudio":{"id":"c1f80510-849c-4134-90a4-644ad1b9068c","dtlsParameters":{"fingerprints":[{"algorithm":"sha-256","value":"2F:0C:C1:1F:5C:90:A4:36:FC:61:27:DF:8B:44:D8:33:47:9E:D1:FC:17:3A:E6:BA:34:E9:CE:53:C2:E4:D1:EA"},{"algorithm":"sha-384","value":"67:10:D2:45:2A:57:AC:06:7A:5F:B7:2D:7B:FD:0A:E3:9D:C5:D2:54:58:A0:6D:B9:31:A9:56:CC:5E:CC:CF:2C:97:CF:D9:1A:1F:5C:12:B2:6F:49:B2:14:8F:14:45:22"},{"algorithm":"sha-1","value":"38:FE:94:EB:D1:12:87:D0:58:58:72:21:0E:AE:93:E4:AA:27:6C:1E"},{"algorithm":"sha-512","value":"BF:CF:47:B6:AF:9E:C5:F1:33:4C:97:98:DD:D3:94:F6:E4:A9:1A:2D:45:87:BD:08:06:68:D6:A6:94:4F:E0:13:B5:FE:E3:23:06:3E:89:99:52:45:24:69:93:DD:8A:77:C6:B7:BC:6F:92:D7:72:13:66:F2:7C:05:DB:DF:41:73"},{"algorithm":"sha-224","value":"95:B0:25:D3:11:9A:96:C0:EC:80:51:C6:E6:21:55:47:8B:EE:92:F9:B4:62:14:48:A0:44:49:62"}],"role":"auto"},"iceCandidates":[{"foundation":"udpcandidate","ip":"20.126.206.57","port":57220,"priority":1076302079,"protocol":"udp","type":"host"},{"foundation":"udpcandidate","ip":"2603:1020:201:10::52","port":31794,"priority":1076276479,"protocol":"udp","type":"host"}],"iceParameters":{"iceLite":true,"password":"9zuvg180gjp8vle0m0f4lmhldwyp02fx","usernameFragment":"n9k96ru2i93i9j8asel2fsfznigrqk93"}}}}]
  • POST https://calldivertsignserver01-pro-west-europe.blue.fermax.com/socket.io/?transport=polling&b64=1&sid=ThePreviousID Body:
750:420["join_call",{"protocolVersion":"0.8.2","appToken":"MyAppToken","fermaxOauthToken":"AuthToken","roomId":"MyDeviceID_1686495975411"}]

Response:

ok
  • GET https://calldivertsignserver01-pro-west-europe.blue.fermax.com/socket.io/?transport=polling&b64=1&sid=ThePreviousID Response:
1306:431[{"result":{"id":"a41d6b20-345f-48d9-88db-00e46d80e915","kind":"video","producerId":"487884e7-1615-40c0-9b93-205dd7822f8c","rtpParameters":{"codecs":[{"mimeType":"video/H264","payloadType":102,"clockRate":90000,"parameters":{"level-asymmetry-allowed":1,"packetization-mode":1,"profile-level-id":"42e01f"},"rtcpFeedback":[{"type":"transport-cc","parameter":""},{"parameter":"fir","type":"ccm"},{"parameter":"","type":"nack"},{"parameter":"pli","type":"nack"}]},{"mimeType":"video/rtx","payloadType":103,"clockRate":90000,"parameters":{"apt":102},"rtcpFeedback":[]}],"headerExtensions":[{"uri":"urn:ietf:params:rtp-hdrext:sdes:mid","id":1,"encrypt":false,"parameters":{}},{"uri":"http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time","id":4,"encrypt":false,"parameters":{}},{"uri":"http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01","id":5,"encrypt":false,"parameters":{}},{"uri":"http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07","id":6,"encrypt":false,"parameters":{}},{"uri":"urn:3gpp:video-orientation","id":11,"encrypt":false,"parameters":{}},{"uri":"urn:ietf:params:rtp-hdrext:toffset","id":12,"encrypt":false,"parameters":{}}],"encodings":[{"ssrc":893115811,"rtx":{"ssrc":893115812}}],"rtcp":{"cname":"5c46dbd2","reducedSize":true,"mux":true},"mid":"0"}}}]
  • POST https://calldivertsignserver01-pro-west-europe.blue.fermax.com/socket.io/?transport=polling&b64=1&sid=ThePreviousID Body:
2067:421["transport_consume",{"producerId":"487884e7-1615-40c0-9b93-205dd7822f8c","rtpCapabilities":{"headerExtensions":[{"uri":"urn:ietf:params:rtp-hdrext:sdes:mid","preferredId":1,"kind":"audio","direction":"sendrecv","preferredEncrypt":false},{"direction":"sendrecv","preferredEncrypt":false,"uri":"urn:ietf:params:rtp-hdrext:sdes:mid","preferredId":1,"kind":"video"},{"preferredId":4,"direction":"sendrecv","preferredEncrypt":false,"uri":"http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/abs-send-time","kind":"audio"},{"direction":"sendrecv","uri":"http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/abs-send-time","preferredEncrypt":false,"kind":"video","preferredId":4},{"preferredId":5,"uri":"http:\/\/www.ietf.org\/id\/draft-holmer-rmcat-transport-wide-cc-extensions-01","preferredEncrypt":false,"kind":"video","direction":"sendrecv"},{"preferredEncrypt":false,"preferredId":6,"direction":"sendrecv","kind":"video","uri":"http:\/\/tools.ietf.org\/html\/draft-ietf-avtext-framemarking-07"},{"uri":"urn:ietf:params:rtp-hdrext:ssrc-audio-level","preferredId":10,"kind":"audio","direction":"sendrecv","preferredEncrypt":false},{"uri":"urn:3gpp:video-orientation","direction":"sendrecv","preferredId":11,"kind":"video","preferredEncrypt":false},{"uri":"urn:ietf:params:rtp-hdrext:toffset","kind":"video","preferredId":12,"direction":"sendrecv","preferredEncrypt":false}],"codecs":[{"kind":"audio","channels":1,"parameters":{},"mimeType":"audio\/PCMA","preferredPayloadType":8,"rtcpFeedback":[],"clockRate":8000},{"mimeType":"video\/H264","parameters":{"profile-level-id":"42e01f","packetization-mode":1,"level-asymmetry-allowed":1},"rtcpFeedback":[{"type":"goog-remb","parameter":""},{"type":"transport-cc","parameter":""},{"parameter":"fir","type":"ccm"},{"parameter":"","type":"nack"},{"parameter":"pli","type":"nack"}],"clockRate":90000,"preferredPayloadType":102,"kind":"video"},{"rtcpFeedback":[],"mimeType":"video\/rtx","parameters":{"apt":102},"clockRate":90000,"preferredPayloadType":103,"kind":"video"}]},"transportId":"eee97d17-b6db-4be7-ab0b-dd69cdaa141e"}]

Response:

ok
  • GET https://calldivertsignserver01-pro-west-europe.blue.fermax.com/socket.io/?transport=polling&b64=1&sid=ThePreviousID Response:
5:432[]
  • POST https://calldivertsignserver01-pro-west-europe.blue.fermax.com/socket.io/?transport=polling&b64=1&sid=ThePreviousID Body:
261:422["transport_connect",{"dtlsParameters":{"role":"client","fingerprints":[{"value":"AA:AA:AA:AA:AA:AA:C1:0C:44:29:EF:85:1B:A5:AA:29:AA:7F:73:C6:F7:AA:C5:2F:F8:E3:AA:AA:AA:AA:AA:AA","algorithm":"sha-256"}]},"transportId":"eee97d17-b6db-4be7-ab0b-dd69cdaa141e"}]

Response:

ok
  • GET https://calldivertsignserver01-pro-west-europe.blue.fermax.com/socket.io/?transport=polling&b64=1&sid=ThePreviousID Response:
1:6

Now video is loaded, then I pressed the green button (call button) but no more HTTP requests where made. Finally, when I ended the call (hang button), /device and /services endpoints are called as before.

Hope this is usefull!

marcosav avatar Jun 11 '23 16:06 marcosav

Thanks for all the request/response bodies. It may be helpful in the future.

I'm not ready yet to create pull request, but I've pushed everything I've done up to this moment to my fork here: https://github.com/yawor/fermax-blue-intercom/tree/rewrite

README file definitely needs a rewrite, as whole command line interface has changed.

When I'm done and this is merged, it would be great to publish this on pypi. Maybe even integrate github actions for automatic build and publish.

yawor avatar Jun 12 '23 18:06 yawor

Hi, would it be possible to add some of the following options?

  • Call History
  • Last event
  • Last picture
  • Take photo

UPDATE: I made a fork of the project in which it was updated with new functions, I leave the link in case you want to take a look. Link to fork

cvc90 avatar Sep 11 '23 14:09 cvc90

Hi, thanks for your work!

Any improvements on this? @yawor your work was amazing, didn't you have time for finishing it?

bvis avatar Dec 27 '23 15:12 bvis

I found this when looking for fermax on github! Did you abandoned the project @yawor? Any advancements?

soloam avatar Apr 17 '24 15:04 soloam

@yawor thanks for your code? Can you confirm if the lates version is on this repository?

simposiummm avatar Nov 12 '24 22:11 simposiummm

Hi,

I'm sorry everyone for the lack of updates. I've had a lot of work recently and I've had not much time for any side projects. Regarding my changes, everything I've done for now is pushed to my repo, but I didn't have time to prepare a proper documentation. That's why I didn't do any pull requests to this original repository.

The current status of my rewrite:

  • It's now fully asychronous. It's based on AnyIO, but tested only on asyncio, so I have no idea if it's going to work on Trio backend.
  • It can be used as both a command line tool and a library to be used in some other software (for example as a library for custom Home Assistant integration).
  • It does't store username and password anywhere. It has an auth command which takes username and password, but uses it only for authentication. What is stored is an access token returned by the Fermax API. It's long lived. I've just tested and my access token from over a year ago still worked today.

yawor avatar Nov 13 '24 17:11 yawor

I got a message today that fermax is going to rebrand and revamp the Blue application into DuoxMe. They are mentioning a better security. I wonder if they are going to introduce a new API together with new app and if yes, then if/when they are planning on phasing out the old one.

yawor avatar Dec 23 '24 13:12 yawor

I got a message today that fermax is going to rebrand and revamp the Blue application into DuoxMe. They are mentioning a better security. I wonder if they are going to introduce a new API together with new app and if yes, then if/when they are planning on phasing out the old one.

Today I updated to the new app (Blue v4.0.0), and It is basically the same thing, at least for the scope of this script, I saw two differences for now:

  • Base URL now is pro-duoxme.fermax.io instead of blue.fermax.io (in former versions blue.fermax.com), but those three point to the same server.
  • Parings uses a new endpoint (v4), which seems to output more data apparently keeping v3 schema. Anyways, v3 parings endpoint is still live.

I will update the script to incorporate this changes, I use it on a daily basis, so if it breaks I will fix it ASAP.

marcosav avatar Jan 08 '25 14:01 marcosav

So, the script is still working with the new endpoint?

cjescudero avatar Feb 08 '25 07:02 cjescudero

So, the script is still working with the new endpoint?

I am working successfully with it from almost 2 years ago without any config change and with 2 doors. It is great!

dacorde avatar Feb 08 '25 10:02 dacorde

Of course, it's very good. It's a pity that only the door opening can be managed, access to the photos would be very useful for security issues and visitor analysis.

If I can, I will try to contribute by adding things that I find interesting:

  • Cache the device_id and the access_id to reduce latency, calling directly with these.
  • Add the option to display the information logs on the output.

cjescudero avatar Feb 08 '25 12:02 cjescudero