Cisco ATA Component - SPA122

I’m working on building out a PyPi package and component for my Cisco ATA (SPA122) that can check to make sure that the phone lines are registered with the VOIP provider, show caller id, see the state of the phone, and add the ability to reboot the device.

If anyone else has one of these VOIP ATAs let me know, I would love to know if others are interested or have an ATA that can help test with.

This should also work with other Cisco ATAs but I have not tested it.

I have the pypi portion of this integration completed. If you have a Cisco ATA you can download it and try the command line utility or module.

I have made a few updates to the python library. It is now updating ever 5 seconds the state of my phone lines and displaying those on the front end. If anyone else is interested in testing this out, let me know. Otherwise I’ll make sure it’s working locally for a bit and then submit a pull request.

Hello @davejcameron , I just tried pyciscospa to get status of my SPA112 and it seems to work like a charm. I intented to use it for monitoring incoming calls and get a notification (for example, show caller ID in kodi while watching tv). If you are willing to share your “ciscospa” custom component, I would definitively be interested!

Thanks!

I’m happy to share the custom component, although it probably needs some work on the code side of things. One thing to note with your use case, I found that the SPA112 wasn’t particularly performant so I couldn’t poll it as frequently as I would have liked which may mean it’s hard to capture the beginning of a call. You can definitely check how long someone has been on the phone, who they are talking to, etc. though.

Don’t worry for the code, I would use it in any state, and I can let you know if I needed to change anything for my use case at the end.
About performance, I just stress-tested client.phones() and I got a stable response time of ~1.62 seconds (by continously calling client.phones() in a loop), so it seems good for my use case if your component polls it every 5 seconds.

I’ve posted the code here on github: https://github.com/davejcameron/custom_components with a sample config. Feel free to fork it, or add a PR if you see issues with the code.

Thanks!
I just tested my use case (show caller ID on all TVs when receiving a call) using your component and it works. I’ll keep this config and observe it for some time.

Below is the config I just tested:

  - id: notify_phone_call
    alias: notify_phone_call
    trigger:
      - platform: state
        entity_id: sensor.phone_1_call_state
        to: 'Ringing'
    action:
      - service: notify.all_kodi
        data_template:
          message: >
            Appel de {{states("sensor.phone_1_call_peer_name")}}

I guess I could need to add a trigger in case the call_peer_name is resolved after the Ringing state, but I’ll wait to see the bug first.

1 Like

Glad it’s working for you, and thanks for sharing your use case.

I tried to install it on my ubuntu server, it install but can’t find the pyciscospa command ?

find -name pyciscospa*
./usr/local/lib/python2.7/dist-packages/pyciscospa-0.1.4.dist-info
./usr/local/lib/python2.7/dist-packages/pyciscospa

I have tried installing the custom component on hass.io v0.97.2 but I get this error in my log:

2019-08-16%2013_40_48-Home%20Assistant

I tried putting the sensor folder from github directly in the config directory and in the custom_component directory.

So I suppose this is not supported anymore?

Hey @mkono87 my HA installation isn’t working 100% right now, and haven’t been using it. The underlying library to talking to the ATA is working fine (AFAIK), my python skills for integrating it into the main HA codebase I never got to and didn’t maintain the custom component with the pace of changes. The code for the pypi library is here: https://github.com/davejcameron/pyciscospa

Thanks for this. I’m actually studying Python is school right now. Maybe something to tackle to improve my skills :slight_smile:

If you getting work, please let’s me know. I would like to use it for my Cisco SPA phone

Yeah would be neat to have, I have a PAP2 which is the same I think

Ive done something with node red insted for my cisco phone spa525g2

[
    {
        "id": "df7cc7040f418ad7",
        "type": "tab",
        "label": "Flow 1",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "3c5063f9e0ced665",
        "type": "inject",
        "z": "df7cc7040f418ad7",
        "name": "Every 5sec",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "Init",
        "payloadType": "str",
        "x": 480,
        "y": 240,
        "wires": [
            [
                "02407f719ab1c167"
            ]
        ]
    },
    {
        "id": "212edf7c8190a22d",
        "type": "xml",
        "z": "df7cc7040f418ad7",
        "name": "Covert the xml into an array",
        "property": "payload",
        "attr": "",
        "chr": "",
        "x": 1100,
        "y": 240,
        "wires": [
            [
                "7cd6d8f0448711ec"
            ]
        ]
    },
    {
        "id": "7cd6d8f0448711ec",
        "type": "change",
        "z": "df7cc7040f418ad7",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "conditions",
                "pt": "flow",
                "to": "payload",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1370,
        "y": 240,
        "wires": [
            [
                "328a807d4769cd70"
            ]
        ]
    },
    {
        "id": "bfe23bc7151217d6",
        "type": "function",
        "z": "df7cc7040f418ad7",
        "name": "is it ringing ?",
        "func": "\n\n\n    var findWhat = msg.payload;\n    var conditions = msg.conditions;\n    var callstate = msg.conditions.Status.Info[0].Line_1_Call_1_Status[0].Call_State[0];\n    if (callstate != \"\")\n    {\n        msg.payload = callstate;\n\n        return msg;\n        \n    }\n\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "// Code added here will be run once\n// whenever the node is started.\nvar loop_count=flow.get('loop') || {};\nif (loop_count==undefined)\n{\n    loop_count=0;\n}",
        "finalize": "",
        "libs": [],
        "x": 750,
        "y": 380,
        "wires": [
            [
                "e6fe5907d63c72bd"
            ]
        ]
    },
    {
        "id": "328a807d4769cd70",
        "type": "change",
        "z": "df7cc7040f418ad7",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "conditions",
                "pt": "msg",
                "to": "conditions",
                "tot": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 530,
        "y": 380,
        "wires": [
            [
                "bfe23bc7151217d6"
            ]
        ]
    },
    {
        "id": "02407f719ab1c167",
        "type": "http request",
        "z": "df7cc7040f418ad7",
        "name": "Read status page from the phone",
        "method": "GET",
        "ret": "txt",
        "paytoqs": "ignore",
        "url": "http://192.168.21.101/admin/status.xml",
        "tls": "",
        "persist": false,
        "proxy": "",
        "authType": "",
        "senderr": false,
        "x": 780,
        "y": 240,
        "wires": [
            [
                "212edf7c8190a22d"
            ]
        ]
    },
    {
        "id": "e6fe5907d63c72bd",
        "type": "function",
        "z": "df7cc7040f418ad7",
        "name": "wich number is callilng",
        "func": "var state = msg.payload\nloop_count = flow.get(\"loop\") || 0;\nnode.status({fill:\"red\",shape:\"ring\",text:loop_count});\nif (loop_count != 1)\n{\n    if (state == \"Ringing\")\n    {\n        var conditions = msg.conditions;\n        callerid = msg.conditions.Status.Info[0].Line_1_Call_1_Status[0].Peer_Phone[0];\n        calleridname = msg.conditions.Status.Info[0].Line_1_Call_1_Status[0].Peer_Name[0]\n        if (calleridname != \"\" )\n        {\n            if (calleridname != \"MONTREAL QC\")\n            {\n                msg.payload = calleridname\n                flow.set(\"loop\",1);\n                return msg;\n            }\n            else\n            {\n                callerid = callerid.split('').join(' ');\n                msg.payload = callerid;\n                flow.set(\"loop\",1);\n                return msg;\n            }\n        }\n        else if (callerid != \"\")\n        {\n            callerid = callerid.split('').join(' ');\n            msg.payload = callerid;\n            flow.set(\"loop\",1);\n            return msg;\n        }\n    }\n}    \n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "// Code added here will be run once\n// whenever the node is started.\nvar loop_count=flow.get('loop') || {};\nif (loop_count==undefined)\n{\n    loop_count=0;\n}",
        "finalize": "",
        "libs": [],
        "x": 1180,
        "y": 380,
        "wires": [
            [
                "cc9393475fddc11d"
            ]
        ]
    },
    {
        "id": "cc9393475fddc11d",
        "type": "api-call-service",
        "z": "df7cc7040f418ad7",
        "name": "",
        "server": "92e9f953.cc4ed8",
        "version": 3,
        "debugenabled": true,
        "service_domain": "tts",
        "service": "cloud_say",
        "entityId": "media_player.annonce_telephone",
        "data": "{\"message\":\"Vous avez un appel de {{payload}}\"}",
        "dataType": "json",
        "mergecontext": "",
        "mustacheAltTags": false,
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "data"
            }
        ],
        "queue": "none",
        "x": 1530,
        "y": 360,
        "wires": [
            [
                "9621e506944a98b1"
            ]
        ]
    },
    {
        "id": "35c35e9bdb6335df",
        "type": "function",
        "z": "df7cc7040f418ad7",
        "name": "Ré-initialiser Loop count a 0",
        "func": "\nflow.set(\"loop\",0);\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 780,
        "y": 480,
        "wires": [
            []
        ]
    },
    {
        "id": "9621e506944a98b1",
        "type": "delay",
        "z": "df7cc7040f418ad7",
        "name": "",
        "pauseType": "delay",
        "timeout": "7",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "allowrate": false,
        "outputs": 1,
        "x": 500,
        "y": 480,
        "wires": [
            [
                "35c35e9bdb6335df"
            ]
        ]
    },
    {
        "id": "92e9f953.cc4ed8",
        "type": "server",
        "name": "Home Assistant 2020",
        "version": 2,
        "addon": false,
        "rejectUnauthorizedCerts": false,
        "ha_boolean": "y|yes|true|on|home|open",
        "connectionDelay": true,
        "cacheJson": true,
        "heartbeat": false,
        "heartbeatInterval": "30"
    }
]

Hello;

Is there a way to have this working on home assistant supervised?

I really want to keep a record of all the call information as history in home assistant.

I tried to no avail to get this working.

It would be nice if there was something that can grab the info into HA.

Hello im kinda stuck .
I have hassio running ,went to terminal and did
pip install pyciscospa

All seems allrgiht despite a working not to use root for such activities.

When I check pip list I see the versione 0.14 installed.

Now I’m not able to find location for the installed file, plus I’m unsure where to put the config .

Could you help ?