Files
claudetools/session-logs/2026-06/2026-06-22-mike-yealink-ymcs-skill.md
Mike Swanson 7f64f169ca sync: auto-sync from GURU-5070 at 2026-06-22 10:03:54
Author: Mike Swanson
Machine: GURU-5070
Timestamp: 2026-06-22 10:03:54
2026-06-22 10:04:41 -07:00

8.4 KiB

Session — yealink-ymcs skill built (YMCS v2 API), pairs with packetdial; vendor-stack correction

User

  • User: Mike Swanson (mike)
  • Machine: GURU-5070
  • Role: admin

Session Summary

Continuation of the VoIP onboarding work. Kept the vwp.91912.service domain created last session and fixed its domain-type to Standard (the create had stored "no"). Then built the onboard-domain wrapper into the packetdial skill — one gated command running the GUI Add-a-Domain flow as 3 API calls (POST /domains → addresses/validate → addresses/create), verified end-to-end with a throwaway create→delete. Mike then clarified the vendor stack (PacketDial = ACG's VoIP-dept brand; NetSapiens = the platform; OIT/OITVOIP = white-label wholesaler) — captured as a reference memory + logged correction.

Mike's main ask: add the related service — Yealink cloud device manager — and make sure we have access + can use it with the PBX skill. Discovery found ACG already has a Yealink admin (admin@azcomputerguru.com, vault infrastructure/voip-phones.sops.yaml) and that the cloud manager is YMCS (us.ymcs.yealink.com); the wiki documents VWP's Yealink T54W fleet. Mike then supplied YMCS API credentials (AccessKey ID + Secret) via screenshot, which were vaulted at services/yealink-ymcs.sops.yaml.

On Mike's go, RTFM'd the YMCS open API and built a new yealink-ymcs skill. The current v2 API uses token auth (POST /v2/token Basic → bearer), not the legacy RPS HMAC signing; Yealink servers require legacy TLS renegotiation. Harvested the full /v2/dm/* + /v2/rps/* endpoint map from the dszp/n8n-nodes-yealinkymcs community node. Implemented ymcs_client.py (token+bearer, legacy-TLS SSL context, paginated _list, vault creds) + ymcs.py CLI (reads + gated writes + raw). Live- verified: token auth, sites, devices (21), accounts, rps-servers. The ACG AccessKey is the parent account that sees ALL client sites (VWP, GuruHQ, Ace Pick Up Parks as children) — so one key covers every client fleet; answers Mike's per-client-vs-one-key question.

The pbx+phone pipeline now exists end to end: packetdial onboard-domain (PBX domain + SIP accounts) → yealink-ymcs (add-devices-by-mac, add-sipaccount to push a NetSapiens SIP cred onto a phone, rps-add for zero-touch via RPS server WL - ACG = ftp://p.packetdials.net). VWP is the live pilot (onboarded to the PBX; 21 devices in YMCS, fleet partly pending). Everything committed, pushed, deployed.

Key Decisions

  • Token auth, not legacy HMAC. The first sources described the old RPS Management Platform HMAC signing (X-Ca-* + Content-MD5); the n8n node revealed the current v2 API uses POST /v2/token (Basic) → bearer. Built to v2 (simpler, current).
  • Legacy TLS handled in-client via an SSL context with OP_LEGACY_SERVER_CONNECT (Yealink servers require renegotiation; default Python TLS would fail).
  • One AccessKey for all clients — verified the key is the ACG parent account; client sites are children. No per-client API keys.
  • add-sipaccount instead of a sip-account list. /v2/dm/sipAccounts (POST) is the CREATE endpoint (not a list); wrapped it as the gated write since pushing a SIP cred onto a phone is the actual PBX↔phone integration glue. No list-sip-accounts exists in v2.
  • Read-first, writes gated --confirm (mirrors packetdial); raw passthrough for the rest.
  • Honest [V]/[P] status in docs — only token/sites/devices/accounts/rps-servers lifecycle- verified; writes + official-firmwares + --site filter are plumbed-but-unverified (no throwaway device to safely test writes on).

Problems Encountered

  • MSYS path conversion on raw: a leading /v2/... arg gets rewritten by Git-Bash to C:/Program Files/Git/v2/.... Added in-code recovery (cut back to /v2/). MSYS_NO_PATHCONV=1 is NOT a fix — it broke the vault subprocess (creds failed). Named wrappers (hardcoded paths) are unaffected. (Documented Windows gotcha class.)
  • /v2/dm/sipAccounts is a create, not a list — my initial sipaccounts read wrapper hit it and got HTTP 400 (sipServer1 cannot be null). Replaced with the gated add-sipaccount.
  • official-firmwares returns a non-standard shape (likely needs a model param) — marked [P].
  • --site filter on devices returned all 21 (siteId in the body didn't scope) — best-effort, marked [P]; full data still returned.
  • cp1252 + WebFetch 403 while RTFMing — used encoding='utf-8' for spec reads and pivoted from the 403'd Yealink doc to the public GitHub n8n node source via the GitHub API + raw files.
  • domain-type stored "no" on packetdial create — fixed vwp via raw PUT (carryover).

Configuration Changes

Created:

  • .claude/skills/yealink-ymcs/SKILL.md, scripts/ymcs.py, scripts/ymcs_client.py (new skill).
  • services/yealink-ymcs.sops.yaml (VAULT) — YMCS API AccessKey.
  • .claude/memory/reference_packetdial_oit_netsapiens.md (+ MEMORY.md index line).
  • This session log. Modified:
  • .claude/skills/packetdial/SKILL.md, scripts/ns.py, scripts/ns_client.pyonboard-domain wrapper.
  • errorlog.md — vendor-model correction. Live changes: vwp domain-type → Standard; threw away acg-onbtest.91912.service (wrapper test).

Credentials & Secrets

  • YMCS API AccessKey — vaulted services/yealink-ymcs.sops.yaml: credentials.access_key_id / credentials.access_key_secret. Region us (us-api.ymcs.yealink.com). Read with vault.sh get-field services/yealink-ymcs.sops.yaml credentials.access_key_id. (Values intentionally not echoed here — they're vaulted.)
  • Existing: Yealink portal admin admin@azcomputerguru.cominfrastructure/voip-phones.sops.yaml; per-client portal logins e.g. clients/valleywide/. PBX reseller key msp-tools/oitvoip.sops.yaml.

Infrastructure & Servers

  • YMCS API: https://us-api.ymcs.yealink.com (v2). Auth POST /v2/token Basic→bearer; legacy TLS.
  • YMCS account tree (ACG parent key): Arizona Computer Guru LLC (id 34a602e7…) → VWP (1e7578a6…), GuruHQ (04117c54…), Ace Pick Up Parks (0320c810…).
  • RPS server: WL - ACG (id 019c908f…), url ftp://p.packetdials.net, authName lrshwh.
  • Device object keys: id, mac, sn, name, modelId/modelName, siteId/siteName, programVersion, deviceStatus, connectWay, wanIp, lanIp, lastReportTime, createTime. 21 devices total.
  • PBX: pbx.packetdial.com/ns-api/v2 (NetSapiens via OIT); domain vwp.91912.service live.

Commands & Outputs

  • YMCS reads: ymcs.py sites|devices|accounts|rps-servers|firmwares|models|alarms|oplogs|device-groups|device-configs
  • YMCS gated writes: ymcs.py add-devices-by-mac|add-sipaccount|reboot|reset|rps-add|rps-del --body '{...}' --confirm
  • ymcs.py raw POST /v2/dm/listDevices --body '{"skip":0,"limit":50,"autoCount":true}' (path auto-recovers MSYS mangling)
  • packetdial onboarding: ns.py onboard-domain --body-file new-client.json --confirm
  • vwp fix: ns.py raw PUT domains/vwp.91912.service --body '{"domain-type":"Standard"}' --confirm

Pending / Incomplete Tasks

  • [P] YMCS writes unverified — add-devices-by-mac, add-sipaccount, reboot, reset, rps add/del; official-firmwares shape; --site device filter. Exercise on real devices (VWP's pending fleet) when a task needs them.
  • Proposed (not started): a combined onboard-client flow = packetdial onboard-domain + users/devices + YMCS phone provisioning (add-by-mac + add-sipaccount/rps) in one gated run, piloted on VWP's 11 pending phones.
  • packetdial gaps (carryover): voicemail user-defaults (not in POST /domains), email-send-from-address pending voicemail@/noreply@packetdial.com mailbox creation.
  • OIT-API.txt plaintext in Downloads — Mike to delete.

Reference Information

  • New skill: .claude/skills/yealink-ymcs/. Vendor stack memory: reference_packetdial_oit_netsapiens.
  • Endpoint map source: github.com/dszp/n8n-nodes-yealinkymcs (n8n community node) + Yealink "Open API for YMCS V4X" doc. Auth doc patterns: support.yealink.com (legacy RPS HMAC — superseded by v2 token).
  • Commits this session: onboard-domain d1d1302d; vendor-stack memory 1dbefd54; yealink-ymcs skill 850e685d. Vault: oitvoip key + YMCS key pushed.
  • YMCS endpoints: /v2/token, /v2/dm/{listSites,listDevices,listAccounts,sipAccounts,addDevicesByMac, addDevices,delDevices,device/reboot,device/reset,listFirmwares,models,...}, /v2/rps/{listServers, listDevices,addDevices,deleteDevices}.