├── .gitignore
├── .vs
├── ProjectSettings.json
├── VSWorkspaceState.json
├── roomdevices-macros-samples
│ ├── FileContentIndex
│ │ ├── c7f82604-b6e1-4fc4-aa35-3142ad8a6a3f.vsidx
│ │ ├── d24c414b-1aa1-47fc-913b-fdb8e8b5712c.vsidx
│ │ └── read.lock
│ └── v17
│ │ ├── .wsuo
│ │ └── TestStore
│ │ └── 0
│ │ ├── 000.testlog
│ │ └── testlog.manifest
└── slnx.sqlite
├── AppleTV Control
├── AppleTV.js
├── README.md
├── appleTV_homescreen.png
├── appleTV_panel_selected.png
├── appletv.xml
└── manifest.json
├── Audio Call Dial Pad
├── .DS_Store
├── ProvisionableApplicationPackage_AudioCall.zip
├── README.md
├── Touch10_AudioCall.png
├── Touch10_homescreen_AudioCall.png
├── audioCall.js
├── audiocall.xml
└── manifest.json
├── Audio Safe Guard
├── Audio Safe Guard.js
├── README.md
├── manifest.json
└── screenshot.png
├── Automatic Room Booking
├── README.md
├── bookRoomWhenInUse.js
├── countdown.png
├── manifest.json
└── prompt.png
├── Automatic Video Mute
├── README.md
├── automute.js
├── manifest.json
└── mute.jpeg
├── BeRightBack
├── README.md
├── badhair.jpeg
├── berightback.js
├── berightback.xml
├── coffee.jpeg
├── confirm.png
├── cooking.jpeg
├── eating.jpeg
├── kids.jpeg
├── manifest.json
├── menu.png
├── preview.png
├── toilet.jpeg
└── toilet.png
├── Big Red Button
├── BigRedButton.js
├── README.md
└── manifest.json
├── Block Outgoing Calls
├── README.md
├── block-outgoing.js
└── manifest.json
├── CONTRIBUTOR.md
├── Camera control with wide angle view
├── Camera Controls.js
├── Camera Controls.xml
├── README.md
├── camera_controls_touch10.png
└── manifest.json
├── Child safe controls
├── Child safe call.js
├── README.md
├── end-call-slider.png
├── endcall.xml
└── incall-view.png
├── Close WebApp
├── CloseWebAppHomeScreen.png
├── CloseWebAppPanel.png
├── README.md
└── WebApp Close.js
├── Conditional Autoanswer with Prompt
├── Conditional Autoanswer.js
├── README.md
└── manifest.json
├── Control Room Devices using USB Input Device
├── QWERTY_Dialling.js
├── README.md
└── RemoteControl.js
├── Custom Config Panel
├── Custom Config demo.xml
├── README.md
└── Room Setup.js
├── Customer Satisfaction Survey
├── README.md
├── customersatisfaction.js
├── customersatisfaction_with_input.js
└── manifest.json
├── Daily Reboot
├── DailyReboot.js
├── README.md
├── daily_reboot.png
└── manifest.json
├── Datadog Call Performance Monitoring
├── Datadog_Dashboard.jpg
├── README.md
├── dashboard.json
├── datadog.js
└── manifest.json
├── Dial Favorite From Homescreen
├── README.md
├── onebuttontodial.js
├── onebuttontodial.png
└── onebuttontodial.xml
├── Early OBTP
├── README.md
├── early-obtp.js
├── manifest.json
├── prompt1.png
└── prompt2.png
├── End Of Meeting Countdown
└── BookingCountdown.js
├── Energy Prices
├── README.md
├── energy-prices.xml
├── energyprice.js
├── energyprices.xml
├── manifest.json
├── screenshot.png
├── screenshot2.png
├── screenshot3.png
└── screenshot4.png
├── Enroll Certificate
├── CertificateEnroll.js
└── README.md
├── Global Macro Messaging
├── Examples
│ ├── GMM_01 Local Example.js
│ ├── GMM_02 RemoteIP Example.js
│ ├── GMM_03 Remote Webex Example.js
│ ├── GMM_04 Queue Example.js
│ ├── GMM_05 Scheduling.js
│ ├── GMM_06 Messages to Webex.js
│ ├── GMM_07 Memory Functions.js
│ └── GMM_Event Receiver.js
├── GMM_Lib.js
├── GMM_Lib.js.zip
├── GMM_wExamples_v1-9-2.zip
├── In_Focus
│ ├── GMM_In Focus.js
│ └── README.MD
├── README.md
├── images
│ ├── DownloadGmmLib.png
│ ├── DownloadGmmLib_Examples.png
│ ├── FormattedMessageBody.png
│ ├── GMM_Visual_IP.jpg
│ ├── GMM_Visual_Local.jpg
│ ├── GMM_Visual_Webex.jpg
│ ├── MessageBody.png
│ └── inFocusHome.png
└── manifest.json
├── HTTP Post - Report Issue
├── .DS_Store
├── ProvisionableApplicationPackage-Report_Issue_with_httpPost.zip
├── README.md
├── ReportIssue.js
├── ReportIssue.xml
├── touch_10_feedbackreceipt.png
├── touch_10_homescreen_reportissue.png
├── touch_10_selectissue.png
├── touch_10_specify_av-issue.png
└── touch_10_specifyissue.png
├── In-Room Control Debugger
├── In-Room Control Debugger.js
└── README.md
├── Instacam
├── README.md
├── instacam.js
├── instacam.xml
├── manifest.json
└── settings-panel.png
├── Join 3rd Party Meeting
├── JoinConferenceButton.png
├── JoinConferencePanel.png
├── JoinMeetingGeneric.js
├── JoinMeetingPanel.xml
├── README.md
└── manifest.json
├── Join Zoom with DTMF Zoom Tools
├── Join Zoom Version 4-1-1.zip
├── JoinZoom_Config_4-1-1.js
├── JoinZoom_JoinText_4-1-1.js
├── JoinZoom_Main_4-1-1.js
├── Memory_Functions.js
├── README.md
├── joinZoom~4-1-1.xml
├── joinZoom~4-1-1~Style_New+Personal.xml
├── joinZoom~4-1-1~Style_New.xml
├── jzoomTools~4-1-1~Tools~Visible.xml
├── jzoomTools~4-1-1~Tools~host.xml
├── jzoomTools~4-1-1~Tools~participant.xml
└── manifest.json
├── LICENSE
├── Language Selector
├── ProvisionableApplicationPackage_language-selector.zip
├── README.md
├── language-selector.js
├── language-selector.xml
├── languageselector_homescreen.png
├── languageselector_panel_selected.png
└── manifest.json
├── Launch Halfwake
├── LaunchHalfwake.js
├── README.md
├── launch-halfwake.png
├── launchhalfwake.xml
└── manifest.json
├── Library - Send Webex Message
├── README.md
├── bot-message.png
├── manifest.json
└── webex.js
├── Library - Weather Forecast
├── README.md
├── lib-weather.js
└── manifest.json
├── Measure Climate
├── README.md
├── climate.xml
├── manifest.json
├── measureclimate.js
└── storage-csv.js
├── Multi-Content Solution
├── MCS Deployment guide.pdf
├── MCS_panel.xml
├── MCS_with_laptop.js
├── MDTDemoPanel.png
├── MDTDemoPanel_RoomOS10.png
├── README.md
├── doctors.jpg
└── manifest.json
├── Philips Hue
├── .gitignore
├── README.md
├── TODO.md
├── examples
│ ├── incall-indicator.js
│ ├── incoming-call-blink.js
│ ├── presence-indicator.js
│ ├── temperature.js
│ ├── virtual-background-panel.xml
│ └── virtual-background.js
├── homescreen.png
├── hue-lib.js
├── hue.jpeg
├── hue.js
├── hue2.jpeg
├── huepanel.xml
├── lights-ui.png
├── manifest.json
├── screenshot.png
└── wizard.png
├── Pin Code Lock
├── README.md
├── manifest.json
├── pin-code.js
└── prompt.png
├── Quiet Mode
├── README.md
├── manifest.json
├── quietmode.js
├── quietmode.png
├── quietmode.xml
├── schedule.js
└── settings.png
├── README.md
├── Remember My Volume
├── README.md
├── RememberMyVolume.js
└── manifest.json
├── Remote Monitoring Alert
├── README.md
├── manifest.json
├── osdUI.png
├── remoteMonitoringAlert.js
├── remoteMonitoringAlert.svg
└── touchUI.png
├── Report Issue
├── README.md
└── manifest.json
├── Room Capacity Alert
├── README.md
├── RoomCapacity.js
├── ScreenshotRoomCapacity.jpeg
└── manifest.json
├── Room Cleaning and Usage
├── README.md
├── RoomCleaningAndUsage.js
├── RoomCleaningAndUsage.xml
├── images
│ ├── panelStats.png
│ ├── roomSummary.png
│ └── roomUsage.png
└── manifest.json
├── Room Kit Pro SX80 GPIO
├── README.md
└── Room Kit Pro SX80 GPIO.js
├── Room Kit Pro Video Compositing
├── CustomMainAndPresentation.js
├── LocalLayoutControls.js
├── README.md
├── roomcontrolconfig_roomkitpro_videocompositing.xml
└── roomcontrolconfig_roomkitpro_videocompositing.zip
├── Room Metrics
├── README.md
├── manifest.json
└── room-metrics.js
├── Samsung Flip
├── README.md
├── flip-and-mini.png
├── flip.xml
├── flipToFlip.js
├── homescreen.png
├── manifest.json
└── samsung-logo.jpeg
├── Scheduled Actions
├── README.md
├── Scheduler.js
└── manifest.json
├── Sennheiser Mute Sync
├── README.md
├── manifest.json
├── sennheiser-lib.js
├── sennheiser-sync.js
└── sennheiser-tcc-m.jpg
├── Settings Pro
├── README.md
├── audio.png
├── immersive.png
├── manifest.json
├── misc.png
├── settings-pro.js
├── settingspro.xml
└── web.png
├── Signage Carousel
├── README.md
├── SignageCarousel.js
├── carousel.png
└── manifest.json
├── Smart Dual Screen Presentation
├── README.md
├── dualScreenPresentation.js
└── dualScreenPresentation.svg
├── Soft Mute
├── README.md
├── manifest.json
├── muted.png
├── notmuted.png
├── soft-mute.js
└── soft-mute.xml
├── Speed Dials Panel
├── README.md
├── Speed Dials.js
├── SpeedDialHomescreen.png
├── SpeedDialOpened.png
├── homescreen.png
├── manifest.json
├── panel.png
└── speed-dials.xml
├── TicTacToe
├── 01_Home.png
├── 02_NewGame.png
├── 03_RandomX.png
├── 04_BlankBoard.png
├── 05_BoardFilling.png
├── 06_XWon.png
├── 07_TieGame.png
├── 08_ContinueFromLast.png
├── README.md
├── TicTacToe.js
└── manifest.json
├── Timer
├── .DS_Store
├── OSD_Timer.png
├── ProvisionableApplicationPackage_Timer.zip
├── README.md
├── Timer.js
├── Timer.xml
├── Touch10_Timer.png
└── Touch10_homescreen_Timer.png
├── USB Mode Version 2
├── CompatibilityMatrix
│ └── readme.md
├── README.md
├── USB Mode V2 Guides.zip
├── USB_Mode_Version_2.js
├── images
│ ├── UsbMode_Enabled.png
│ ├── UsbMode_Home.png
│ ├── icon
│ │ ├── button_click-to-download-usb-mode-deployment-guides-and-macro.png
│ │ ├── button_download-deployment-guide.png
│ │ ├── green.png
│ │ ├── red.png
│ │ └── yellow.png
│ └── thumbnails
│ │ └── thumb_usb2_configuration.png
└── manifest.json
├── Unbook Empty Room
├── README.md
├── UnbookEmptyRoom.js
└── manifest.json
├── Web App with Cache Management
├── README.md
├── WebAppClearCache.js
└── manifest.json
├── WebApps Manager
├── README.md
├── WebApps Manager.js
├── WebAppsManager.gif
└── manifest.json
├── Working From Home
├── README.md
├── client-status.png
├── device-screen.png
├── manifest.json
├── prompt.png
└── wfh.js
├── macro-list.json
├── make-manifest.js
├── manifest-template.json
├── roomos.png
├── run-macro
└── universal-adapter.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/.vs/ProjectSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "CurrentProjectSetting": null
3 | }
--------------------------------------------------------------------------------
/.vs/VSWorkspaceState.json:
--------------------------------------------------------------------------------
1 | {
2 | "ExpandedNodes": [
3 | "",
4 | "\\Early OBTP",
5 | "\\Multi-Content Solution"
6 | ],
7 | "SelectedNode": "\\Multi-Content Solution\\MCS_panel.xml",
8 | "PreviewInSolutionExplorer": false
9 | }
--------------------------------------------------------------------------------
/.vs/roomdevices-macros-samples/FileContentIndex/c7f82604-b6e1-4fc4-aa35-3142ad8a6a3f.vsidx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/.vs/roomdevices-macros-samples/FileContentIndex/c7f82604-b6e1-4fc4-aa35-3142ad8a6a3f.vsidx
--------------------------------------------------------------------------------
/.vs/roomdevices-macros-samples/FileContentIndex/d24c414b-1aa1-47fc-913b-fdb8e8b5712c.vsidx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/.vs/roomdevices-macros-samples/FileContentIndex/d24c414b-1aa1-47fc-913b-fdb8e8b5712c.vsidx
--------------------------------------------------------------------------------
/.vs/roomdevices-macros-samples/FileContentIndex/read.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/.vs/roomdevices-macros-samples/FileContentIndex/read.lock
--------------------------------------------------------------------------------
/.vs/roomdevices-macros-samples/v17/.wsuo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/.vs/roomdevices-macros-samples/v17/.wsuo
--------------------------------------------------------------------------------
/.vs/roomdevices-macros-samples/v17/TestStore/0/000.testlog:
--------------------------------------------------------------------------------
1 | !!tItseT
--------------------------------------------------------------------------------
/.vs/roomdevices-macros-samples/v17/TestStore/0/testlog.manifest:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/.vs/roomdevices-macros-samples/v17/TestStore/0/testlog.manifest
--------------------------------------------------------------------------------
/.vs/slnx.sqlite:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/.vs/slnx.sqlite
--------------------------------------------------------------------------------
/AppleTV Control/appleTV_homescreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/AppleTV Control/appleTV_homescreen.png
--------------------------------------------------------------------------------
/AppleTV Control/appleTV_panel_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/AppleTV Control/appleTV_panel_selected.png
--------------------------------------------------------------------------------
/AppleTV Control/appletv.xml:
--------------------------------------------------------------------------------
1 |
2 | 1.5
3 |
4 | panel-1
5 | Home
6 | Tv
7 | 1
8 | Apple TV
9 |
10 | Apple TV
11 |
12 | Row
13 |
14 | appletv_navigator
15 | DirectionalPad
16 | size=4
17 |
18 |
19 | appletv_menu
20 | Button
21 | size=1;icon=list
22 |
23 |
24 | appletv_play
25 | Button
26 | size=1;icon=play_pause
27 |
28 |
29 | AppleTV
30 | hideRowNames=1
31 |
32 |
33 |
--------------------------------------------------------------------------------
/AppleTV Control/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "./AppleTV.js",
8 | "type": "url",
9 | "id": "appletv"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": [
15 | {
16 | "payload": "./appletv.xml",
17 | "type": "url",
18 | "id": "appletv"
19 | }
20 | ]
21 | },
22 | "userParams": [
23 | {
24 | "id": "CONNECTOR_APPLE_TV",
25 | "name": "Connector id",
26 | "info": "Which input connector on video device is the Apple TV connected to?",
27 | "type": "number",
28 | "default": 2,
29 | "domain": "appletv",
30 | "required": true
31 | }
32 | ]
33 | },
34 | "profileName": "backup-tbjolset",
35 | "generatedAt": "20210526-1707"
36 | }
37 |
--------------------------------------------------------------------------------
/Audio Call Dial Pad/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Audio Call Dial Pad/.DS_Store
--------------------------------------------------------------------------------
/Audio Call Dial Pad/ProvisionableApplicationPackage_AudioCall.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Audio Call Dial Pad/ProvisionableApplicationPackage_AudioCall.zip
--------------------------------------------------------------------------------
/Audio Call Dial Pad/README.md:
--------------------------------------------------------------------------------
1 | # Audio Call
2 | Create a UI extension that adds a dedicated audio call dial pad to the touch controller.
3 |
4 | ---
5 | Snapshot of Touch Controller Home Screen Panel with Audio Dialler:
6 | 
7 | Snapshot of Touch Controller Home Screen Panel after pressing the Audio Dialler:
8 | 
9 | ---
10 |
11 |
12 | ## Requirements
13 | 1. Cisco Video room device (Room Kit devices only)
14 | 2. Firmware CE9.3.0 or newer.
15 |
16 |
17 | ## Disclaimer
18 | This example is only a sample and is **NOT guaranteed to be bug free and production quality**.
19 |
20 | The sample macros are meant to:
21 | - Illustrate how to use the CE Macros.
22 | - Serve as an example of the step-by-step process of building a macro using JavaScript and integration with the device xAPI
23 | - Provided as a guide for a developer to see how to initialize a macro and set up handlers for user and dialog updates.
24 |
25 | The sample macros are made available to Cisco partners and customers as a convenience to help minimize the cost of Cisco Finesse customizations. Cisco does not permit the use of this library in customer deployments that do not include Cisco Video Endpoint Hardware.
26 |
27 | ## Support Notice
28 | [Support](http://developer.cisco.com/site/devnet/support) for the macros is provided on a "best effort" basis via DevNet. Like any custom deployment, it is the responsibility of the partner and/or customer to ensure that the customization works correctly and this includes ensuring that the macro is properly integrated into 3rd party applications.
29 |
30 | It is Cisco's intention to ensure macro compatibility across versions as much as possible and Cisco will make every effort to clearly document any differences in the xAPI across versions in the event that a backwards compatibility impacting change is made.
31 |
32 | Cisco Systems, Inc.
33 | [http://www.cisco.com](http://www.cisco.com)
34 | [http://developer.cisco.com/site/roomdevices](http://developer.cisco.com/site/roomdevices)
35 |
--------------------------------------------------------------------------------
/Audio Call Dial Pad/Touch10_AudioCall.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Audio Call Dial Pad/Touch10_AudioCall.png
--------------------------------------------------------------------------------
/Audio Call Dial Pad/Touch10_homescreen_AudioCall.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Audio Call Dial Pad/Touch10_homescreen_AudioCall.png
--------------------------------------------------------------------------------
/Audio Call Dial Pad/audioCall.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 |
3 | const KEYBOARD_TYPES = {
4 | NUMERIC : 'Numeric'
5 | , SINGLELINE : 'SingleLine'
6 | , PASSWORD : 'Password'
7 | , PIN : 'PIN'
8 | }
9 | const CALL_TYPES = {
10 | AUDIO : 'Audio'
11 | , VIDEO : 'Video'
12 | }
13 |
14 | const DIALPAD_ID = 'dialpad';
15 | const INROOMCONTROL_AUDIOCONTROL_PANELID = 'audiocall';
16 |
17 | /* Use these to check that its a valid number (depending on what you want to allow users to call */
18 | const REGEXP_URLDIALER = /([a-zA-Z0-9@_\-\.]+)/; /* . Use this one if you want to allow URL dialling */
19 | const REGEXP_NUMERICDIALER = /^([0-9]{3,10})$/; /* Use this one if you want to limit calls to numeric only. In this example, require number to be between 3 and 10 digits. */
20 |
21 | const DIALPREFIX_AUDIO_GATEWAY = '0';
22 |
23 | function showDialPad(text){
24 |
25 | xapi.command("UserInterface Message TextInput Display", {
26 | InputType: KEYBOARD_TYPES.NUMERIC
27 | , Placeholder: "Use keypad to enter number"
28 | , Title: "Audio Call"
29 | , Text: text
30 | , SubmitText: "Call"
31 | , FeedbackId: DIALPAD_ID
32 | }).catch((error) => { console.error(error); });
33 | }
34 |
35 | /* This is the listener for the in-room control panel button that will trigger the dial panel to appear */
36 | xapi.event.on('UserInterface Extensions Panel Clicked', (event) => {
37 | if(event.PanelId === INROOMCONTROL_AUDIOCONTROL_PANELID){
38 | showDialPad("Enter the number you want to dial:" );
39 | }
40 | });
41 |
42 |
43 | /* Event listener for the dial pad been posted */
44 |
45 | xapi.event.on('UserInterface Message TextInput Response', (event) => {
46 | switch(event.FeedbackId){
47 | case DIALPAD_ID:
48 |
49 | var regex =REGEXP_URLDIALER; //change this to whatever filter you want to check for validity
50 | var match = regex.exec(event.Text);
51 | if (match !== null) {
52 | var numbertodial = match[1];
53 | numbertodial = DIALPREFIX_AUDIO_GATEWAY + numbertodial; // Here you can do some massaging of the number to dial, e.g. if it need prefixing or postfixing
54 | xapi.command("dial", {Number: numbertodial, CallType: CALL_TYPES.AUDIO}).catch((error) => { console.error(error); });
55 |
56 | }
57 | else{
58 | showDialPad("You typed in an invalid number. Please try again. Format is blablabla..." );
59 | }
60 | break;
61 | }
62 | });
63 |
64 |
--------------------------------------------------------------------------------
/Audio Call Dial Pad/audiocall.xml:
--------------------------------------------------------------------------------
1 | 1.5
2 | audiocall
3 | Home
4 | Handset
5 | 1
6 | #30D557
7 | Audio Call
8 |
9 |
--------------------------------------------------------------------------------
/Audio Call Dial Pad/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "audioCall.js",
8 | "id": "audioCall",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": [
15 | {
16 | "payload": "audiocall.xml",
17 | "id": "audiocall",
18 | "type": "url"
19 | }
20 | ]
21 | },
22 | "userParams": []
23 | }
24 | }
--------------------------------------------------------------------------------
/Audio Safe Guard/Audio Safe Guard.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Limit the volume of a video system to a user definede level < 100.
3 | * Show a message if this happens
4 | */
5 | import xapi from 'xapi';
6 |
7 | const MAX_VOLUME = 70;
8 |
9 | function setVolume(vol) {
10 | xapi.command('Audio Volume Set', { Level: vol });
11 | }
12 |
13 | function alert(title, text, duration = 5) {
14 | xapi.command('UserInterface Message Alert Display', {
15 | Title: title,
16 | Text: text,
17 | Duration: duration,
18 | });
19 | }
20 |
21 | function limitVolume(volume) {
22 | if (volume > MAX_VOLUME) {
23 | setVolume(MAX_VOLUME);
24 | alert('Volume restricted', 'Max volume on this video system is restriced by a script');
25 | }
26 | }
27 |
28 | function checkInitialVolume() {
29 | xapi.status
30 | .get('Audio Volume')
31 | .then((volume) => { limitVolume(volume); })
32 | .catch((error) => { console.error(error); });
33 | }
34 |
35 | function init() {
36 | xapi.status.on('Audio Volume', (volume) => {
37 | console.log(`Volume changed to: ${volume}`);
38 | limitVolume(volume);
39 | });
40 | checkInitialVolume();
41 | }
42 |
43 | init();
44 |
--------------------------------------------------------------------------------
/Audio Safe Guard/README.md:
--------------------------------------------------------------------------------
1 | # Learning: Audio safe guard
2 | If user tries to adjust volume below a treshold you set, the macro automatically sets the volume back to the max limit.
3 |
4 | 
5 |
6 | This macro shows you how to:
7 | - Listen to changes to the system (feedback on status)
8 | - React to change and set values (command)
9 | - Notify users about your macro (user interface alert)
10 |
11 | ## Requirements
12 |
13 | Works on all devices.
14 |
--------------------------------------------------------------------------------
/Audio Safe Guard/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "Audio Safe Guard.js",
8 | "id": "Audio Safe Guard",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": []
15 | },
16 | "userParams": [
17 | {
18 | "id": "MAX_VOLUME",
19 | "name": "Max volume",
20 | "info": "The limit at which volume will be capped (0-100)",
21 | "type": "number",
22 | "default": 70,
23 | "domain": "Audio Safe Guard",
24 | "required": true
25 | }
26 | ]
27 | }
28 | }
--------------------------------------------------------------------------------
/Audio Safe Guard/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Audio Safe Guard/screenshot.png
--------------------------------------------------------------------------------
/Automatic Room Booking/countdown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Automatic Room Booking/countdown.png
--------------------------------------------------------------------------------
/Automatic Room Booking/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "bookRoomWhenInUse.js",
8 | "id": "bookRoomWhenInUse",
9 | "type": "url"
10 | }
11 | ]
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/Automatic Room Booking/prompt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Automatic Room Booking/prompt.png
--------------------------------------------------------------------------------
/Automatic Video Mute/README.md:
--------------------------------------------------------------------------------
1 | # Automatic Video Mute
2 |
3 | With this extension you will automatically mute your video as well anytime you mute
4 | your audio - and unmute your video again when you unmute your audio.
5 |
6 | If you manually mute/unmute your video (from call controls) it will not affect your audio mute.
7 |
8 | 
--------------------------------------------------------------------------------
/Automatic Video Mute/automute.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This macro makes your video mute stay in sync with your audio mute,
3 | * ie if you mute/unmute your audio, it will also mute/unmute your video.
4 | * So basically one physical button to completely mute/unmute yourself.
5 | *
6 | * Note: manually muting/unmuting video will not affect audio mute.
7 | *
8 | * @author Cyprien Simons
9 | **/
10 |
11 | import xapi from 'xapi';
12 |
13 | xapi.Event.Audio.MicrophonesMuteStatus.on((value) => {
14 | if (value.Mute === 'On') {
15 | xapi.Command.Video.Input.MainVideo.Mute();
16 | } else {
17 | xapi.Command.Video.Input.MainVideo.Unmute();
18 | }
19 | });
20 |
--------------------------------------------------------------------------------
/Automatic Video Mute/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "automute.js",
8 | "id": "automute",
9 | "type": "url"
10 | }
11 | ]
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/Automatic Video Mute/mute.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Automatic Video Mute/mute.jpeg
--------------------------------------------------------------------------------
/BeRightBack/README.md:
--------------------------------------------------------------------------------
1 | # Be Right Back
2 |
3 | Set a virtual background displaying that you are away from device while in call, but still on audio.
4 |
5 | ---
6 |
7 | On a video call on your Cisco Desk device, but need to step away for a bit, but still listening on audio? Let your colleagues know by setting a setting an availabily status like image as virtual background while you are away.
8 |
9 | The extension will automatically detect when you are back in front of the device, and ask if you would like to remove the notice.
10 |
11 | 
12 | 
13 | 
14 | 
15 | ---
16 |
17 | ## Requirements
18 |
19 | 1. Cisco Desk device (Desk Pro, Desk, Desk Mini etc)
20 | 2. Firmware CE10 or newer.
21 | 3. Admin user access to endpoint
22 | 4. Coffee
23 |
24 | ## Usage
25 |
26 | * Install the extension.
27 | * A 'Be right back' button will appear in your call controls when you are in a call
28 | * Tap it to choose your status when you step away from the desk
29 | * When the system detects you are back in front of your device (with camera sensor), it will ask you if you want to disable the virtual background again
30 |
31 | ## Tweaking
32 |
33 | You can easily edit the macro and:
34 |
35 | * Set your own background images instead
36 | * Set what kind of background you go back to after exiting Be Right Back mode
37 |
--------------------------------------------------------------------------------
/BeRightBack/badhair.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/BeRightBack/badhair.jpeg
--------------------------------------------------------------------------------
/BeRightBack/berightback.xml:
--------------------------------------------------------------------------------
1 |
2 | 1.9
3 |
4 | 1
5 | berightback
6 | local
7 | CallControls
8 | Power
9 | #875AE0
10 | Be Right Back
11 | Custom
12 |
13 | Be right back
14 |
15 | Row
16 |
17 | widget_1
18 | Set a virtual background while you are away from the device
19 | Text
20 | size=4;fontSize=small;align=left
21 |
22 |
23 |
24 | Set mode
25 |
26 | berightback_img
27 | GroupButton
28 | size=4;columns=3
29 |
30 |
31 | coffee
32 | ☕️ Coffee
33 |
34 |
35 | eating
36 | 🍴 Eating
37 |
38 |
39 | kids
40 | 🙉 Kids
41 |
42 |
43 | badhair
44 | 👩🎤 Bad Hair
45 |
46 |
47 | toilet
48 | 🚽 Toilet
49 |
50 |
51 | none
52 | ⛔️ None
53 |
54 |
55 |
56 |
57 |
58 | Row
59 |
60 | widget_2
61 | Note: Your self view is mirrored, but far end sees the text correctly.
62 | Text
63 | size=4;fontSize=small;align=left
64 |
65 |
66 | hideRowNames=1
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/BeRightBack/coffee.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/BeRightBack/coffee.jpeg
--------------------------------------------------------------------------------
/BeRightBack/confirm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/BeRightBack/confirm.png
--------------------------------------------------------------------------------
/BeRightBack/cooking.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/BeRightBack/cooking.jpeg
--------------------------------------------------------------------------------
/BeRightBack/eating.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/BeRightBack/eating.jpeg
--------------------------------------------------------------------------------
/BeRightBack/kids.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/BeRightBack/kids.jpeg
--------------------------------------------------------------------------------
/BeRightBack/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "./berightback.js",
8 | "type": "url",
9 | "id": "berightback"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": [
15 | {
16 | "payload": "./berightback.xml",
17 | "type": "url",
18 | "id": "berightback"
19 | }
20 | ]
21 | }
22 | },
23 | "profileName": "backup-tbjolset",
24 | "generatedAt": "20210526-1707"
25 | }
26 |
--------------------------------------------------------------------------------
/BeRightBack/menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/BeRightBack/menu.png
--------------------------------------------------------------------------------
/BeRightBack/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/BeRightBack/preview.png
--------------------------------------------------------------------------------
/BeRightBack/toilet.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/BeRightBack/toilet.jpeg
--------------------------------------------------------------------------------
/BeRightBack/toilet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/BeRightBack/toilet.png
--------------------------------------------------------------------------------
/Big Red Button/BigRedButton.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 |
3 | const action = 'toggleMute';
4 |
5 | function toggleMute() {
6 | xapi.Command.Audio.Microphones.ToggleMute();
7 | }
8 |
9 | async function toggleHalfwake() {
10 | const state = await xapi.Status.Standby.State.get();
11 | if (state === 'Halfwake') {
12 | xapi.Command.Standby.Deactivate();
13 | }
14 | else {
15 | xapi.Command.Standby.Halfwake();
16 | }
17 | }
18 |
19 | async function onKey({ Key, Type }) {
20 | if (Type !== 'Released') return;
21 |
22 | if (Key === 'KEY_SPACE') {
23 | console.log('go!');
24 | const calls = await xapi.Status.Call.get();
25 | const inCall = calls.length > 0;
26 | if (inCall) {
27 | if (action === 'toggleMute') {
28 | toggleMute();
29 | }
30 | else if (action === 'endCall') {
31 | xapi.Command.Call.Disconnect();
32 | }
33 | }
34 | else {
35 | toggleHalfwake();
36 | }
37 | }
38 | }
39 |
40 | function init() {
41 | xapi.Config.Peripherals.InputDevice.Mode.set('On')
42 | .catch(() => console.error('Looks like your device doesnt support USB peripherals'));
43 | xapi.Event.UserInterface.InputDevice.Key.Action
44 | .on(onKey);
45 | }
46 |
47 | init();
48 |
--------------------------------------------------------------------------------
/Big Red Button/README.md:
--------------------------------------------------------------------------------
1 | # Big Red Button
2 |
3 | Have a quick action for a big red physical USB button, such as muting yourself.
4 |
5 | 
6 |
7 | Most of the Webex devices support connecting a USB peripheral. If the USB device acts as a keyboard, you can listen to events from it with macros.
8 |
9 | ## Requirements
10 |
11 | * Any newer Webex device that supports [xConfiguration Peripherals InputDevice Mode](https://roomos.cisco.com/xapi/Configuration.Peripherals.InputDevice.Mode/)
12 | * A USB device that acts as a USB keyboard
13 |
--------------------------------------------------------------------------------
/Big Red Button/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "BigRedButton.js",
8 | "id": "BigRedButton",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": []
15 | },
16 | "userParams": [
17 | {
18 | "id": "action",
19 | "name": "In-call action",
20 | "info": "What happens when tapping button in call",
21 | "type": "option",
22 | "values": {
23 | "toggleMute": "Mute yourself",
24 | "endCall": "End call"
25 | },
26 | "domain": "BigRedButton"
27 | }
28 | ]
29 | }
30 | }
--------------------------------------------------------------------------------
/Block Outgoing Calls/README.md:
--------------------------------------------------------------------------------
1 | # Block Outgoing Calls
2 |
3 | Block certain numbers in a reject list from being called from the system. Show a message on screen instead.
4 |
5 | Open the macro in the macro editor and add more numbers to the list if you need to.
6 |
7 | **NOTE**: If you are using this extension on Webex Edge, edit the macro and set the delay timeout to 5 seconds, otherwise the blocking will not take place.
8 |
--------------------------------------------------------------------------------
/Block Outgoing Calls/block-outgoing.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 |
3 | // variable that can be changed from settings ui on roomos.cisco.com
4 | const NumberToBlock = 'macro.polo@cisco.com';
5 |
6 | const delayBlockSec = 0; // For webex edge, set this to 5
7 |
8 | const denyList = [
9 | NumberToBlock,
10 |
11 | // add more numbers like this if you need to:
12 | // 'thedude@cisco.com',
13 | ];
14 |
15 | xapi.Status.Call.on(e => {
16 | if (!e || !e.RemoteNumber) return;
17 |
18 | const reject = denyList.some(number => number.toLowerCase().includes(e.RemoteNumber.toLowerCase()));
19 | const outgoing = e.Direction === 'Outgoing';
20 | if (outgoing && reject) {
21 | xapi.Command.UserInterface.Message.Alert.Display({
22 | Text: 'The number you called was not allowed by a user script on the device',
23 | Duration: 10,
24 | });
25 | setTimeout(() => {
26 | xapi.Command.Call.Disconnect();
27 | }, delayBlockSec * 1000);
28 | }
29 | });
30 |
--------------------------------------------------------------------------------
/Block Outgoing Calls/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "./block-outgoing.js",
8 | "type": "url",
9 | "id": "block-outgoing"
10 | }
11 | ]
12 | },
13 | "userParams": [
14 | {
15 | "id": "NumberToBlock",
16 | "name": "Number to block",
17 | "info": "Partial number is also ok",
18 | "type": "string",
19 | "default": "macro.polo@cisco.com",
20 | "domain": "block-outgoing",
21 | "required": true
22 | }
23 | ]
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Camera control with wide angle view/Camera Controls.xml:
--------------------------------------------------------------------------------
1 |
2 | 1.5
3 |
4 | cameracontrolpanel
5 | Statusbar
6 | Camera
7 | 1
8 | Camera Control
9 |
10 | Camera Control
11 |
12 | Set active camera
13 |
14 | camera_left
15 | Left
16 | Button
17 | size=1
18 |
19 |
20 | camera_right
21 | Right
22 | Button
23 | size=1
24 |
25 |
26 | camera_wide
27 | Both (Wide Angle)
28 | Button
29 | size=2
30 |
31 |
32 |
33 | Camera Control
34 |
35 | cameracontrol
36 | DirectionalPad
37 | size=4
38 |
39 |
40 | cameracontrol
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/Camera control with wide angle view/README.md:
--------------------------------------------------------------------------------
1 | # Camera Controls
2 | Allows the user to control multiple cameras using the touch controller. It also shows how to do simple video compositing stitching two cameras together as one wide angle image.
3 |
4 | As a bonus, it also shows how to control whatever camera(s) are selected as the main source from one single UI extension.
5 |
6 | ---
7 | Snapshot of Touch Controller Home Screen Panel for the camera control selector:
8 | 
9 | ---
10 |
11 |
12 | ## Requirements
13 | 1. Cisco Video room device (Room Kit or SX80)
14 | 2. Firmware CE9.2.1 or newer.
15 | 4. Admin user access to endpoint
16 |
17 | ## Usage
18 | 1. Read the document [Working with Macros and In-room Controls](https://www.cisco.com/c/dam/en/us/td/docs/telepresence/endpoint/ce92/sx-mx-dx-room-kit-customization-guide-ce92.pdf) for a comprehensive introduction to UI extensions and macros; as well as step-by-step instructions on how to build and upload your code.
19 |
20 | ## Setup
21 | 1. Connect two cameras to the Room Devices in two HDMI Inputs.
22 |
23 |
24 |
25 | ## Disclaimer
26 | This example is only a sample and is **NOT guaranteed to be bug free and production quality**.
27 |
28 | The sample macros are meant to:
29 | - Illustrate how to use the CE Macros.
30 | - Serve as an example of the step-by-step process of building a macro using JavaScript and integration with the device xAPI
31 | - Provided as a guide for a developer to see how to initialize a macro and set up handlers for user and dialog updates.
32 |
33 | The sample macros are made available to Cisco partners and customers as a convenience to help minimize the cost of Cisco Finesse customizations. Cisco does not permit the use of this library in customer deployments that do not include Cisco Video Endpoint Hardware.
34 |
35 | ## Support Notice
36 | [Support](http://developer.cisco.com/site/devnet/support) for the macros is provided on a "best effort" basis via DevNet. Like any custom deployment, it is the responsibility of the partner and/or customer to ensure that the customization works correctly and this includes ensuring that the macro is properly integrated into 3rd party applications.
37 |
38 | It is Cisco's intention to ensure macro compatibility across versions as much as possible and Cisco will make every effort to clearly document any differences in the xAPI across versions in the event that a backwards compatibility impacting change is made.
39 |
40 | Cisco Systems, Inc.
41 | [http://www.cisco.com](http://www.cisco.com)
42 | [http://developer.cisco.com/site/roomdevices](http://developer.cisco.com/site/roomdevices)
43 |
--------------------------------------------------------------------------------
/Camera control with wide angle view/camera_controls_touch10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Camera control with wide angle view/camera_controls_touch10.png
--------------------------------------------------------------------------------
/Camera control with wide angle view/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "Camera Controls.js",
8 | "id": "Camera Controls",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": [
15 | {
16 | "payload": "Camera Controls.xml",
17 | "id": "Camera Controls",
18 | "type": "url"
19 | }
20 | ]
21 | },
22 | "userParams": []
23 | }
24 | }
--------------------------------------------------------------------------------
/Child safe controls/Child safe call.js:
--------------------------------------------------------------------------------
1 | // child safe end call slider
2 | import xapi from 'xapi';
3 |
4 | function guiEvent(e) {
5 | if (e.WidgetId === 'end-call' && e.Type === 'released' && e.Value > 225) {
6 | xapi.command('Call Disconnect');
7 | xapi.command('UserInterface Extensions Panel Close');
8 | // reset slider for next time:
9 | xapi.command('UserInterface Extensions Widget SetValue', { WidgetId: 'end-call', Value: 0 });
10 | }
11 | }
12 |
13 | function alert(title, text = '', duration = 5) {
14 | xapi.command('UserInterface Message Alert Display', {
15 | Title: title,
16 | Text: text,
17 | Duration: duration,
18 | });
19 | }
20 |
21 | function setEndCallVisible(visible) {
22 | xapi.config.set('UserInterface Features Call End', visible ? 'Auto' : 'Hidden');
23 | }
24 |
25 | function init() {
26 | xapi.config.set('UserInterface Features Call End', 'Auto');
27 | xapi.event.on('UserInterface Extensions Widget Action', guiEvent);
28 |
29 | // prevent mute in call (child safety)
30 | xapi.status.on('Audio Microphones Mute', val => {
31 | if (val === 'On') {
32 | xapi.command('Audio Microphones Unmute');
33 | alert('Mute is disabled by a child safety macro.');
34 | }
35 | });
36 |
37 | // we turn on/off the hide end button each time we start/stop the call, so if the macro is removed
38 | // the end call is always showing again
39 | xapi.Status.Call.on((e) => {
40 | if (new Date().getHours() >= 19) return; // kids are sleeping anyways
41 |
42 | xapi.Status.Call.get()
43 | .then((list) => {
44 | const inCall = list.length > 0;
45 | setEndCallVisible(!inCall);
46 | });
47 | })
48 | }
49 |
50 | init();
--------------------------------------------------------------------------------
/Child safe controls/README.md:
--------------------------------------------------------------------------------
1 | # Child Safe Controls
2 | Replace the end call button with a slider to end the call.
3 |
4 | 
5 |
6 | Kids love hitting the red end call button, this macro replaces the button with a panel with a slider where you must drag the slider across to end the call.
7 |
8 | 
9 |
10 | The normal end call is available at night when the kids are sleeping.
11 |
12 | In addition, the mute button is also disabled.
13 |
--------------------------------------------------------------------------------
/Child safe controls/end-call-slider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Child safe controls/end-call-slider.png
--------------------------------------------------------------------------------
/Child safe controls/endcall.xml:
--------------------------------------------------------------------------------
1 |
2 | 1.8
3 |
4 | 1
5 | end-call
6 | local
7 | InCall
8 | Handset
9 | #FF503C
10 | End call
11 | Custom
12 |
13 | End call
14 |
15 | Row
16 |
17 | end-call
18 | Slider
19 | size=4
20 |
21 |
22 | widget_2
23 | Drag slider to the right to end call
24 | Text
25 | size=4;fontSize=normal;align=center
26 |
27 |
28 | hideRowNames=1
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Child safe controls/incall-view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Child safe controls/incall-view.png
--------------------------------------------------------------------------------
/Close WebApp/CloseWebAppHomeScreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Close WebApp/CloseWebAppHomeScreen.png
--------------------------------------------------------------------------------
/Close WebApp/CloseWebAppPanel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Close WebApp/CloseWebAppPanel.png
--------------------------------------------------------------------------------
/Conditional Autoanswer with Prompt/Conditional Autoanswer.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 |
3 | /*
4 |
5 | This macro demonstrates how to have a conditional autoanswer on a system. The macro, upon incoming call, checks whether the remote site is listed in the list of numbers to be auto answered.
6 | If it finds it, it prompts for a few seconds to allow for either an immediate answer OR to reject the call
7 | */
8 |
9 | const AUTOANSWER_NUMBERS = ['mynumber@example.com', 'myothernumber@example.com'];
10 | const AUTOANSWER_DELAY_SECONDS = 10;
11 | var autoanswerhandler;
12 |
13 |
14 | function normaliseRemoteURI(number){
15 | var regex = /^(sip:|h323:|spark:|h320:|webex:|locus:)/gi;
16 | number = number.replace(regex, '');
17 | // console.log('Normalised Remote URI to ' + number);
18 | return number;
19 | }
20 |
21 | function answerCall(){
22 | xapi.command('Call Accept').catch(
23 | (error) =>{
24 | console.error(error);
25 | });
26 | }
27 |
28 | xapi.event.on('IncomingCallIndication', (event) => {
29 | console.log(event);
30 | if(AUTOANSWER_NUMBERS.includes(normaliseRemoteURI(event.RemoteURI))){
31 | xapi.command("UserInterface Message Alert Display", {Title: 'Incoming Autoanswer-number', Text: 'This call will automatically be answered after ' + AUTOANSWER_DELAY_SECONDS + ' seconds', Duration: AUTOANSWER_DELAY_SECONDS});
32 | autoanswerhandler = setTimeout(() => answerCall(), AUTOANSWER_DELAY_SECONDS * 1000);
33 | }
34 | });
35 |
36 |
37 | xapi.status.on('Call Status', (status) => {
38 | if(status === 'Connected'){
39 | clearTimeout(autoanswerhandler);
40 | // console.log('Call was accepted before auto-answer was performed');
41 | xapi.command("UserInterface Message Alert Clear");
42 | }
43 | });
44 |
45 | xapi.event.on('CallDisconnect', (event) => {
46 | clearTimeout(autoanswerhandler);
47 | // console.log('Call was disconnected before auto-answer was performed');
48 | xapi.command("UserInterface Message Alert Clear");
49 | });
50 |
--------------------------------------------------------------------------------
/Conditional Autoanswer with Prompt/README.md:
--------------------------------------------------------------------------------
1 | # Conditional auto answered
2 | Auto answer on incoming calls - but only for a select number of remote sites
3 |
4 | You can add one or more numbers in the allow list. If an incoming call doesn't match the list, the incoming call dialog is shown as usual. Otherwise, the call is automatically accepted after a user-defined delay.
5 |
--------------------------------------------------------------------------------
/Conditional Autoanswer with Prompt/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "Conditional Autoanswer.js",
8 | "id": "Conditional Autoanswer",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": []
15 | },
16 | "userParams": []
17 | }
18 | }
--------------------------------------------------------------------------------
/Custom Config Panel/README.md:
--------------------------------------------------------------------------------
1 | ## Custom configuration panel
2 | A custom panel that allows users to control configs that are available on the API, but not to users through the default user interface.
3 |
--------------------------------------------------------------------------------
/Customer Satisfaction Survey/README.md:
--------------------------------------------------------------------------------
1 | # Customer Satisfaction Survey
2 | Pop up a satisfaction survey at the end of a call.
3 |
--------------------------------------------------------------------------------
/Customer Satisfaction Survey/customersatisfaction.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 |
3 | xapi.event.on('CallDisconnect', (event) => {
4 | if(event.Duration > 0){
5 | xapi.command("UserInterface Message Prompt Display", {Title: "How was the meeting experience", Text: 'How would you rate this demo', 'Option.1':'Wow, that was cool!!!', 'Option.2':'It was OK', 'Option.3': 'That was it? You suck!'});
6 | }
7 | else{
8 | xapi.command("UserInterface Message Prompt Display", {Title: "What went wrong?", Text: 'Hm, no call. What happened?', 'Option.1':'I dialled the wrong number!', 'Option.2':"I don't know" , 'Option.3': 'oops, wrong button'});
9 | }
10 | });
11 |
12 |
13 |
14 |
15 | xapi.event.on('UserInterface Message Prompt Response', (event) => {
16 | var displaytitle = '';
17 | var displaytext = '';
18 | switch(event.OptionId){
19 | case '1':
20 | displaytitle = ':-)';
21 | displaytext = 'Thank you, yet another satisfied customer!!!';
22 | break;
23 | case '2':
24 | displaytitle = ':-\\';
25 | displaytext = 'Ok, will try even harder the next time';
26 | break;
27 | case '3':
28 | displaytitle = ':-(';
29 | displaytext = 'Oops, sorry I will not disappoint you the next time';
30 | break;
31 |
32 | default:
33 | displaytext = 'Hm, that was an unhandled answer';
34 | }
35 | xapi.command("UserInterface Message Alert Display", {Title: displaytitle, Text: displaytext, Duration: 8});
36 | });
37 |
--------------------------------------------------------------------------------
/Customer Satisfaction Survey/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "customersatisfaction.js",
8 | "id": "customersatisfaction",
9 | "type": "url"
10 | },
11 | {
12 | "payload": "customersatisfaction_with_input.js",
13 | "id": "customersatisfaction_with_input",
14 | "type": "url"
15 | }
16 | ]
17 | },
18 | "roomcontrol": {
19 | "items": []
20 | },
21 | "userParams": []
22 | }
23 | }
--------------------------------------------------------------------------------
/Daily Reboot/DailyReboot.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 |
3 | //Define hour and minute for boot every day (device time)
4 | const hourBoot = 3; // 0-23 (Default 3am, numbers are without leading zeroes)
5 | const minuteBoot = 0; // 0-59 (Default sharp)
6 | const leadingZero = (number) => (number < 10 ? `0${number}` : number);
7 |
8 | function rebootTimer() {
9 |
10 | const now = new Date();
11 | const targetRebootTime = new Date(now.getFullYear(), now.getMonth(), now.getDate(), hourBoot, minuteBoot, 0, 0);
12 | const timeUntilBoot = targetRebootTime - now;
13 |
14 | if (timeUntilBoot > 0) { // Test boot time if its upcoming or in the past
15 |
16 | setTimeout(readyForBoot, timeUntilBoot);
17 | console.log(`Setting reboot timer for today at ${leadingZero(hourBoot)}:${leadingZero(minuteBoot)}... (Daily reboot scheduler macro)`);
18 |
19 | } else { // If time has passed this day, set targetRebootTime for tomorrow
20 |
21 | targetRebootTime.setDate(targetRebootTime.getDate() + 1);
22 |
23 | const nextBootTime = targetRebootTime - now;
24 |
25 | setTimeout(readyForBoot, nextBootTime);
26 |
27 | console.log(`Defined time has passed for today, setting next reboot timer at ${leadingZero(hourBoot)}:${leadingZero(minuteBoot)} tomorrow... (Daily Reboot scheduler macro)`);
28 |
29 | }
30 | }
31 |
32 | async function readyForBoot() { // Safety function, test if the device is part of a call before reboot, other tests can be added here if needed
33 |
34 | const testState = (v) => !['Initialized', 'Sleeping'].includes(v)
35 | var state = await xapi.Status.SystemUnit.State.System.get()
36 |
37 | console.log(state)
38 |
39 | if (testState(state)) { // Part of an active call? Postpone for 1 hour
40 |
41 | console.log(`Device seems not to be ready for reboot due to device state being: ${state}. Postponing reboot for 1 hour.. (Daily Reboot scheduler macro)`)
42 | setTimeout(readyForBoot, 60 * 60 * 1000)
43 |
44 | } else { // Not part of a call, go ahead and reboot
45 |
46 | boot();
47 |
48 | }
49 | }
50 | function boot() {
51 |
52 | xapi.Command.SystemUnit.Boot();
53 | console.log('Executing scheduled reboot... (Daily Reboot scheduler macro)');
54 |
55 | }
56 |
57 | rebootTimer();
--------------------------------------------------------------------------------
/Daily Reboot/README.md:
--------------------------------------------------------------------------------
1 | # Cisco CE / RoomOS / MTR Video Endpoints Macros - DailyReboot
2 |
3 | This macro is designed to perform a daily reboot of the Cisco CE/RoomOS/MTR video endpoints. If the device is in an active call at the scheduled reboot time, the reboot will be postponed for one hour.
4 |
5 | ---
6 |
7 | 
8 |
9 | ---
10 |
11 | ## Requirements
12 | 1. Cisco Room Device
13 | 2. Firmware RoomOS 10.19.1.x or newer.
14 | 3. Devices running MTR must be registered on Control Hub for this macro to work.
15 |
16 | ## Configuration steps
17 | Edit the following constants:
18 |
19 | - 'hourBoot' to specify the hour of the day for the device reboot (values: 0-23)
20 | - 'minuteBoot' to specify the minute of the specified 'hourBoot' (values: 0-59)
21 |
22 | For example, if you set 'hourBoot' to 21 and 'minuteBoot' to 10, the device will reboot at 21:10 on the same or next day, depending on when the macro was initiated.
23 |
24 | - Note: The time used is the device timezone.
25 | - Note: The hours and minutes are configured without a leading zero. 3 for 3am not 03.
26 |
27 | ## How it works
28 |
29 | Upon launching the macro, it will retrieve the current time and check if the specified 'hourBoot' and 'minuteBoot' have already passed for the current day or are scheduled for the future. If the specified time has already passed, the macro will automatically schedule the reboot for the same hour on the next day.
30 |
31 | If the device is engaged in an active call at the scheduled reboot time, the reboot will be repeatedly postponed for a duration of 1 hour until the device becomes available and is no longer in a call.
32 |
33 | ## Support for this macro
34 |
35 | For support related to this macro, please contact Magnus Ohm (mohm@cisco.com). Contacting via the Webex Messenging App is preferred.
36 |
37 |
--------------------------------------------------------------------------------
/Daily Reboot/daily_reboot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Daily Reboot/daily_reboot.png
--------------------------------------------------------------------------------
/Daily Reboot/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "./DailyReboot.js",
8 | "id": "DailyReboot",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": []
15 | },
16 | "userParams": [
17 | {
18 | "id": "hourBoot",
19 | "name": "Hour of boot time (0-23)",
20 | "info": "Number is required",
21 | "type": "number",
22 | "default": 21,
23 | "domain": "DailyReboot",
24 | "required": true
25 | },
26 | {
27 | "id": "minuteBoot",
28 | "name": "Minute of boot time (0-59)",
29 | "info": "Number is required",
30 | "type": "number",
31 | "default": 30,
32 | "domain": "DailyReboot",
33 | "required": true
34 | }
35 | ]
36 | }
37 | }
--------------------------------------------------------------------------------
/Datadog Call Performance Monitoring/Datadog_Dashboard.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Datadog Call Performance Monitoring/Datadog_Dashboard.jpg
--------------------------------------------------------------------------------
/Datadog Call Performance Monitoring/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "./datadog.js",
8 | "type": "url",
9 | "id": "datadog"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": []
15 | },
16 | "userParams": [
17 | {
18 | "id": "DD_TOKEN",
19 | "name": "Datadog Client Token",
20 | "info": "Get from https://app.datadoghq.com/organization-settings/client-tokens",
21 | "type": "string",
22 | "default": "REPLACE_ME",
23 | "domain": "datadog",
24 | "required": true
25 | },
26 | {
27 | "id": "DD_TAGS",
28 | "name": "Datadog Tags",
29 | "info": "Comma Delimited, adds important metadata to your performance data",
30 | "type": "string",
31 | "default": "env:stg,team:rocket",
32 | "domain": "datadog",
33 | "required": true
34 | },
35 | {
36 | "id": "CHECK_IF_CALL_FREQUENCY",
37 | "name": "Call Check Frequency",
38 | "info": "Frequency that the device will check if there is an active call to monitor",
39 | "type": "number",
40 | "default": 60000,
41 | "domain": "datadog",
42 | "required": true
43 | },
44 | {
45 | "id": "IN_CALL_CHECK_FREQUENCY",
46 | "name": "In-Call Collection Frequency",
47 | "info": "Frequency that the device will collect data if there is an active call to monitor",
48 | "type": "number",
49 | "default": 60000,
50 | "domain": "datadog",
51 | "required": true
52 | },
53 | {
54 | "id": "GENERAL_CHECK_FREQUENCY",
55 | "name": "General Collection Frequency",
56 | "info": "Frequency that the device will collect general device status data",
57 | "type": "number",
58 | "default": 300000,
59 | "domain": "datadog",
60 | "required": true
61 | },
62 | {
63 | "id": "MONITOR_PERIPHERALS",
64 | "name": "Monitor Peripherals",
65 | "info": "Do you want to monitor the connection status of peripheral devices",
66 | "type": "bool",
67 | "default": true,
68 | "domain": "datadog",
69 | "required": true
70 | }
71 | ]
72 | },
73 | "profileName": "stephenlechner",
74 | "generatedAt": "20220317-1201"
75 | }
--------------------------------------------------------------------------------
/Dial Favorite From Homescreen/onebuttontodial.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 |
3 | const MYSPEED_DIAL_NUMBER = 'mynumber@mydomain.com';
4 |
5 | xapi.event.on('UserInterface Extensions Page Action', (event) => {
6 | if(event.Type == 'Opened' && event.PageId == 'speed_dial'){
7 | xapi.command("dial", {Number: MYSPEED_DIAL_NUMBER});
8 | }
9 | });
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Dial Favorite From Homescreen/onebuttontodial.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Dial Favorite From Homescreen/onebuttontodial.png
--------------------------------------------------------------------------------
/Dial Favorite From Homescreen/onebuttontodial.xml:
--------------------------------------------------------------------------------
1 |
2 | 1.4
3 |
4 | Handset
5 | Home
6 |
7 | Dialling
8 |
9 | Row
10 |
11 | text
12 | Number is being dialled
13 | Text
14 | size=4;align=center;fontSize=normal
15 |
16 |
17 | speed_dial
18 | hideRowNames=1
19 |
20 | Press me to dial
21 |
22 |
--------------------------------------------------------------------------------
/Early OBTP/README.md:
--------------------------------------------------------------------------------
1 | # Early One Button To Push (OBTP)
2 |
3 | 
4 |
5 | This macro and UI Extension was created to provide an easy way to early dial into future meetings with a single button. The main use case is to have time to test setups and make sure everything is in order more than 5 minutes prior to meeting start. It was initially built for a customer wanting to be able to dial into various meetings the executives attended, but it turned out to be more demand for this feature, so here it is.
6 |
7 |
8 | **Author: Svein Terje Steffensen and Marcel Neidinger**
9 |
10 | Update, March 2023: This functionality may now be enabled natively in the user interface but enabling the EarlyJoin feature: [xConfiguration UserInterface Bookings Visibility EarlyJoin](https://roomos.cisco.com/xapi/Configuration.UserInterface.Bookings.Visibility.EarlyJoin/)
11 |
12 | ---
13 | Snapshot of Room Navigator after the "Early OBTP" button has been pressed and there are no upcomping meetings:
14 | 
15 | ---
16 |
17 |
18 | ## Requirements
19 | 1. Device must have some form of calendar integration to have bookings pushed to the device.
20 | 2. Not supported by devices in Personal mode
21 | 3. The booking must contain an alphanumeric URI - WebRTC meetings not supported
22 |
23 |
24 | ## Usage
25 | 1. Add the macro and UI extension. When pressing the "Early OBTP"-panel, a prompt with up to 5 upcoming bookings will appear, and if you select one, the device will dial the number accosiacted with the booking.
26 |
27 |
28 | ## Disclaimer
29 | This code is tested and found working with RoomOS 10.20.0 with RoomOS 11 preview applied. It may still contain errors, so please report issues found.
30 |
31 | The macro is made available to Cisco partners and customers as a convenience to help simplify daily operations. Cisco does not permit the use of this library in customer deployments that do not include Cisco Video Endpoint Hardware.
32 |
33 | ## Support Notice
34 | [Support](http://developer.cisco.com/site/devnet/support) for the macros is provided on a "best effort" basis via DevNet. Like any custom deployment, it is the responsibility of the partner and/or customer to ensure that the customization works correctly and this includes ensuring that the macro is properly integrated into 3rd party applications.
35 |
36 | It is Cisco's intention to ensure macro compatibility across versions as much as possible and Cisco will make every effort to clearly document any differences in the xAPI across versions in the event that a backwards compatibility impacting change is made.
37 |
38 | Cisco Systems, Inc.
39 | [http://www.cisco.com](http://www.cisco.com)
40 | [http://developer.cisco.com/site/roomdevices](http://developer.cisco.com/site/roomdevices)
--------------------------------------------------------------------------------
/Early OBTP/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "early-obtp.js",
8 | "id": "early-obtp",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": [
15 | ]
16 | },
17 | "userParams": []
18 | }
19 | }
--------------------------------------------------------------------------------
/Early OBTP/prompt1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Early OBTP/prompt1.png
--------------------------------------------------------------------------------
/Early OBTP/prompt2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Early OBTP/prompt2.png
--------------------------------------------------------------------------------
/End Of Meeting Countdown/BookingCountdown.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 |
3 | let startTime = -1; // minutes
4 | let timeLeft = 0; // seconds
5 | let timer = 0;
6 |
7 | const Sound = 'CallWaiting';
8 |
9 | function showMsg(text, duration = 5) {
10 | xapi.command('UserInterface Message TextLine Display', {
11 | Text: text,
12 | Duration: duration,
13 | X: 9000,
14 | Y:500
15 | });
16 | }
17 |
18 | function showAlert(title, text, duration = 5) {
19 | xapi.command('UserInterface Message Alert Display', {
20 | Title: title,
21 | Text: text,
22 | Duration: duration,
23 | });
24 | }
25 |
26 | function clearScreen() {
27 | xapi.command('UserInterface Message TextLine Clear');
28 | }
29 |
30 |
31 | function formatTime(time) {
32 | let min = Math.floor(time / 60);
33 | if (min < 10) min = `0${min}`;
34 | let sec = time % 60;
35 | if (sec < 10) sec = `0${sec}`;
36 | return `${min}:${sec}`;
37 | }
38 |
39 | function playSound() {
40 | xapi.command('Audio Sound Play', { Sound });
41 | setTimeout(() => xapi.command('Audio Sound Stop'), 8000);
42 | }
43 |
44 |
45 | function stopTimer() {
46 | clearTimeout(timer);
47 | timer = 0;
48 | }
49 |
50 | function timerFinished() {
51 | cancel();
52 | playSound();
53 | setTimeout(() => playSound(), 2000); // play twice
54 | const msg = 'Time is up!';
55 | showAlert('00:00', msg, 30, 2);
56 | }
57 |
58 | function showTime() {
59 | const text = `Time left of scheduled meeting: ${formatTime(timeLeft)}`;
60 | showMsg(text, 2);
61 | }
62 |
63 | function tick() {
64 |
65 | if (timeLeft < 0) timerFinished();
66 | else{
67 | timer = setTimeout(tick, 1000);
68 | showTime();
69 | }
70 | timeLeft--;
71 | }
72 |
73 | function startTimer() {
74 | showTime();
75 | tick();
76 | }
77 |
78 |
79 | function start(seconds) {
80 | cancel();
81 | startTime = Math.max(1, parseInt(seconds));
82 | timeLeft = startTime;
83 | startTimer();
84 | }
85 |
86 | function cancel() {
87 | console.log('cancel');
88 | clearScreen();
89 | stopTimer();
90 | startTime = -1;
91 | }
92 |
93 | function onGuiEvent(e) {
94 | if (e.Type !== 'released' || e.WidgetId !== ButtonPreset) return;
95 | if (parseInt(e.Value) === startTime || e.Value === 0) cancel();
96 | else start(e.Value);
97 | }
98 |
99 | xapi.Event.Bookings.TimeRemaining.on(event => {
100 | start(event.Seconds);
101 | })
102 |
103 |
--------------------------------------------------------------------------------
/Energy Prices/README.md:
--------------------------------------------------------------------------------
1 | # Norwegian Energy Prices
2 |
3 | Show the hourly Norwegian electricy price on the home screen, in the bottom left corner ('custom message').
4 | Optionally also provides a home screen button to show a plot of todays prices.
5 |
6 | Zone map: https://norgesenergi.no/hjelp/strompriser/historiske-strompriser/
7 |
8 | Source: https://norway-power.ffail.win/?zone=NO1&date=2021-12-20 etc
9 |
10 | 
11 | 
12 |
13 | The spot price for the current hour is displayed in the bottom left corner, as well as an arrow indicating whether the price will rise or fall the next hour.
14 |
15 | ## Code example
16 |
17 | This is also a nice and simple example/tutorial of how to:
18 |
19 | * Fetch data from external APIs
20 | * Plot data easily in a web view without having your own web server (using quickcharts.io)
21 | * Provide user options when installing extensions (see manifest.json)
22 | * Make an integration that works on both touch screen and non-touch-screen devices
23 |
--------------------------------------------------------------------------------
/Energy Prices/energy-prices.xml:
--------------------------------------------------------------------------------
1 |
2 | 1.8
3 |
4 | 8
5 | energy-prices
6 | local
7 | Home
8 | Power
9 | #FC5143
10 | Energy prizes
11 | Custom
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Energy Prices/energyprices.xml:
--------------------------------------------------------------------------------
1 |
2 | 1.8
3 |
4 | 8
5 | energy-prices
6 | local
7 | Home
8 | Power
9 | #FC5143
10 | Energy prizes
11 | Custom
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Energy Prices/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "./energyprice.js",
8 | "type": "url",
9 | "id": "energyprices"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": [
15 | {
16 | "payload": "./energy-prices.xml",
17 | "id": "energy-prices",
18 | "type": "url"
19 | }
20 | ]
21 | },
22 | "userParams": [
23 | {
24 | "id": "zone",
25 | "name": "Energy Zone",
26 | "info": "Which Norwegian energy zone you belong to",
27 | "type": "option",
28 | "values": {
29 | "NO1": "Zone 1 - South/East Norway",
30 | "NO2": "Zone 2 - South Norway",
31 | "NO3": "Zone 3 - Central Norway",
32 | "NO4": "Zone 4 - North Norway",
33 | "NO5": "Zone 5 - West Norway"
34 | },
35 | "domain": "energy-prices",
36 | "required": true
37 | },
38 | {
39 | "id": "hasPlotPanel",
40 | "name": "Show plot panel",
41 | "info": "Add home screen button to show daily price plot",
42 | "type": "bool",
43 | "domain": "energy-prices",
44 | "default": true
45 | }
46 | ],
47 | "uninstall": [
48 | { "type": "config", "path": "Standby Signage Mode", "value": "Off" },
49 | { "type": "config", "path": "FacilityService Service 5 Name", "value": "" }
50 | ]
51 |
52 | },
53 | "profileName": "backup-tbjolset",
54 | "generatedAt": "20210526-1707"
55 | }
56 |
--------------------------------------------------------------------------------
/Energy Prices/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Energy Prices/screenshot.png
--------------------------------------------------------------------------------
/Energy Prices/screenshot2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Energy Prices/screenshot2.png
--------------------------------------------------------------------------------
/Energy Prices/screenshot3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Energy Prices/screenshot3.png
--------------------------------------------------------------------------------
/Energy Prices/screenshot4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Energy Prices/screenshot4.png
--------------------------------------------------------------------------------
/Enroll Certificate/README.md:
--------------------------------------------------------------------------------
1 | # Enroll Certificate
2 |
3 | Add Locally Significate Certificate (LSC) using SCEP RFC8894 for Certificate Enrollment.
4 |
5 | ## Requirements
6 |
7 | 1. CA/RA with SCEP Server URL
8 | 1. CA Fingerprint of the Signing CA Certificate
9 | 1. CA Certificates for IEEE 802.1X TlsVerify
10 |
11 | ## Parameters
12 |
13 | NOTE: Any optional parameters not being used should be left alone with the default value to ignore.
14 |
15 | 1. SCEP Server Url
16 | 1. CA Fingerprint
17 | 1. Challenge Password - if configured on SCEP Server
18 | 1. CSR Distinguished Name (DN) details - /C /ST /L /O /OU /CN
19 | 1. Purpose - Usages for the Certificate after being installed.
20 | See [documentation](https://roomos.cisco.com/xapi/Command.Security.Certificates.Services.Activate/) for a list of purposes.
21 | 1. CA Certificate PEM - NOTE: The "dot" on final newline is required.
22 |
23 | ## Limitations
24 |
25 | 1. Can only be used to install 1 LSC. Macro will not run if any LSC is already installed on device.
26 | 1. Can only add up to 3 CA Certificates in BEGIN/END CERTIFICATE blocks (added before the period).
27 | 1. Only one Organization Unit can be added since the enrollargs key must be unique.
28 | 1. CSR Subject Alt Name (SAN) values (ip: email: dns: uri:) may be added to the script.
29 | If needed, follow the example of the other CSR parameters.
30 |
31 | ## Support Notice
32 |
33 | [Support](http://developer.cisco.com/site/devnet/support) for the macros is provided on a "best effort" basis via DevNet. Like any custom deployment, it is the responsibility of the partner and/or customer to ensure that the customization works correctly and this includes ensuring that the macro is properly integrated into 3rd party applications.
34 |
35 | It is Cisco's intention to ensure macro compatibility across versions as much as possible and Cisco will make every effort to clearly document any differences in the xAPI across versions in the event that a backwards compatibility impacting change is made.
36 |
37 | Cisco Systems, Inc.
38 | [http://www.cisco.com](http://www.cisco.com)
39 | [http://developer.cisco.com/site/roomdevices](http://developer.cisco.com/site/roomdevices)
40 |
--------------------------------------------------------------------------------
/Global Macro Messaging/Examples/GMM_05 Scheduling.js:
--------------------------------------------------------------------------------
1 | /********************************************************
2 | Copyright (c) 2022 Cisco and/or its affiliates.
3 | This software is licensed to you under the terms of the Cisco Sample
4 | Code License, Version 1.1 (the "License"). You may obtain a copy of the
5 | License at
6 | https://developer.cisco.com/docs/licenses
7 | All use of the material herein must be in accordance with the terms of
8 | the License. All rights not expressly granted by the License are
9 | reserved. Unless required by applicable law or agreed to separately in
10 | writing, software distributed under the License is distributed on an "AS
11 | IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12 | or implied.
13 | *********************************************************
14 |
15 | * Author: Robert(Bobby) McGonigle Jr
16 | * Technical Marketing Engineer
17 | * Cisco Systems
18 | * bomcgoni@cisco.com
19 | *
20 | *
21 | * Consulting Engineer: Gerardo Chaves
22 | * Technical Solutions Architect
23 | * Cisco Systems
24 | *
25 | *
26 | * Released: May 21, 2022
27 | * Updated: June 21, 2022
28 | *
29 | * Description:
30 | * - Example 4 for the GMM_lib
31 | * - Be sure to review examples [1, 2, 3, 4] before continuing
32 | * - Review this before moving onto the next Example
33 | *
34 | * Script Dependencies
35 | * - GMM_Lib
36 | * - Library for GMM
37 | * - Have this installed, saved, and remain disabled. It is imported into each example
38 | * - GMM_Event Receiver
39 | * - Used for examples
40 | * - Have this installed and enabled on all Room Devices you use as you navigate through examples 1-4
41 | *
42 | */
43 |
44 | import xapi from 'xapi';
45 | import { GMM } from './GMM_Lib'
46 |
47 | /*
48 | Schedule tasks
49 |
50 | As the name suggests, you can schedule a task on a specific hour and minute
51 | by using the GMM.Event.Schedule.on('time', event =>{}) subscription
52 |
53 | //This is a modified function of the Scheduled Actions macro found on roomos.cisco.com
54 | https://roomos.cisco.com/macros/Scheduled%20Actions
55 | */
56 |
57 | //This subscription takes a 24hr format time and will fire an event once per day at
58 | // given time, per the devices local time
59 | GMM.Event.Schedule.on('04:00', event => {
60 | console.log(event) // Log output: '{ Message: '[04:00] Scheduled event fired' }'
61 | //Run the code you need to run at 4am here
62 | })
63 |
64 | GMM.Event.Schedule.on('14:00', event => {
65 | console.log(event) // Log output: '{ Message: '[14:00] Scheduled event fired' }'
66 | //Run the code you need to run at 2pm here
67 | })
--------------------------------------------------------------------------------
/Global Macro Messaging/GMM_Lib.js.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Global Macro Messaging/GMM_Lib.js.zip
--------------------------------------------------------------------------------
/Global Macro Messaging/GMM_wExamples_v1-9-2.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Global Macro Messaging/GMM_wExamples_v1-9-2.zip
--------------------------------------------------------------------------------
/Global Macro Messaging/images/DownloadGmmLib.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Global Macro Messaging/images/DownloadGmmLib.png
--------------------------------------------------------------------------------
/Global Macro Messaging/images/DownloadGmmLib_Examples.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Global Macro Messaging/images/DownloadGmmLib_Examples.png
--------------------------------------------------------------------------------
/Global Macro Messaging/images/FormattedMessageBody.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Global Macro Messaging/images/FormattedMessageBody.png
--------------------------------------------------------------------------------
/Global Macro Messaging/images/GMM_Visual_IP.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Global Macro Messaging/images/GMM_Visual_IP.jpg
--------------------------------------------------------------------------------
/Global Macro Messaging/images/GMM_Visual_Local.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Global Macro Messaging/images/GMM_Visual_Local.jpg
--------------------------------------------------------------------------------
/Global Macro Messaging/images/GMM_Visual_Webex.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Global Macro Messaging/images/GMM_Visual_Webex.jpg
--------------------------------------------------------------------------------
/Global Macro Messaging/images/MessageBody.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Global Macro Messaging/images/MessageBody.png
--------------------------------------------------------------------------------
/Global Macro Messaging/images/inFocusHome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Global Macro Messaging/images/inFocusHome.png
--------------------------------------------------------------------------------
/Global Macro Messaging/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "GMM_Lib.js",
8 | "id": "GMM_Lib",
9 | "type": "library"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": []
15 | },
16 | "userParams": []
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/HTTP Post - Report Issue/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/HTTP Post - Report Issue/.DS_Store
--------------------------------------------------------------------------------
/HTTP Post - Report Issue/ProvisionableApplicationPackage-Report_Issue_with_httpPost.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/HTTP Post - Report Issue/ProvisionableApplicationPackage-Report_Issue_with_httpPost.zip
--------------------------------------------------------------------------------
/HTTP Post - Report Issue/ReportIssue.xml:
--------------------------------------------------------------------------------
1 |
2 | 1.5
3 |
4 | reportissue
5 | Statusbar
6 | Concierge
7 | 1
8 | #FF3D67
9 | Report Issue
10 |
11 |
12 |
--------------------------------------------------------------------------------
/HTTP Post - Report Issue/touch_10_feedbackreceipt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/HTTP Post - Report Issue/touch_10_feedbackreceipt.png
--------------------------------------------------------------------------------
/HTTP Post - Report Issue/touch_10_homescreen_reportissue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/HTTP Post - Report Issue/touch_10_homescreen_reportissue.png
--------------------------------------------------------------------------------
/HTTP Post - Report Issue/touch_10_selectissue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/HTTP Post - Report Issue/touch_10_selectissue.png
--------------------------------------------------------------------------------
/HTTP Post - Report Issue/touch_10_specify_av-issue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/HTTP Post - Report Issue/touch_10_specify_av-issue.png
--------------------------------------------------------------------------------
/HTTP Post - Report Issue/touch_10_specifyissue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/HTTP Post - Report Issue/touch_10_specifyissue.png
--------------------------------------------------------------------------------
/In-Room Control Debugger/In-Room Control Debugger.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 |
3 | // Generic Event handler for in-room control extensions
4 |
5 | function showInRoomControlEvent(eventtext){
6 | eventtext = eventtext.replace(/\"/g,"'"); // replace double quotes wiht single quotes for rendering purposes
7 | console.log(eventtext);
8 | xapi.command("UserInterface Message TextLine Display", {Text: eventtext, Duration: 3});
9 |
10 | }
11 |
12 | xapi.event.on('UserInterface Extensions Widget LayoutUpdated', (event) => {
13 | showInRoomControlEvent('A new version of the in-room control layouts was uploaded to the codec');
14 | });
15 |
16 |
17 | xapi.event.on('UserInterface Extensions Page Action', (event) => {
18 | var message = 'In-Room Control Page-event. PageId:"' + event.PageId + '" Event: "' + event.Type +'"';
19 | // console.log(message);
20 | showInRoomControlEvent(message);
21 |
22 | // Example of usage:
23 | if(event.PageId == 'MyPageId'){
24 | if(event.Type == 'Opened'){
25 | console.log(`Page ${event.PageId} was opened`);
26 | }
27 | else if(event.Type == 'Closed'){
28 | console.log(`Page ${event.PageId} was closed`);
29 | }
30 | }
31 |
32 |
33 | });
34 |
35 |
36 |
37 | xapi.event.on('UserInterface Extensions Widget Action', (event) => {
38 | var message = 'In-Room Control Widget-event. WidgetId:"' + event.WidgetId + '" Event: "' + event.Type +'" Value: "' + event.Value +'"';
39 | // console.log(message);
40 | showInRoomControlEvent(message);
41 |
42 | /*
43 | // Example of usage:
44 | if(event.WidgetId == 'myWidgetId'){
45 | if(event.Type == 'clicked'){
46 | console.log(`myWidgetId was Clicked`);
47 | xapi.command("dial", {number: 'somenumber@mydomain.com'});
48 | }
49 | }
50 | */
51 |
52 | });
--------------------------------------------------------------------------------
/In-Room Control Debugger/README.md:
--------------------------------------------------------------------------------
1 | # In-Room Control Debugger
2 | Display events as they occur in a notification on the main screen. Quick way to learn how the API works.
3 |
--------------------------------------------------------------------------------
/Instacam/README.md:
--------------------------------------------------------------------------------
1 | # Instacam
2 |
3 | Tweak the color saturation and color compenstation of your Desk device.
4 |
5 | 
6 |
7 | Requirement
8 | * Device that has the new xAPI for color saturation: **xConfiguration Cameras Camera ColorSaturation Level**
--------------------------------------------------------------------------------
/Instacam/instacam.xml:
--------------------------------------------------------------------------------
1 |
2 | 1.10
3 |
4 | 1
5 | instacam
6 | local
7 | HomeScreen
8 | Camera
9 | #1170CF
10 | Instacam
11 | Custom
12 |
13 | Instacam
14 |
15 | Info
16 |
17 | instacam-info
18 | Tweak how your image appears to the other participants
19 | Text
20 | size=4;fontSize=normal;align=left
21 |
22 |
23 |
24 | Color saturation
25 |
26 | instacam-saturation
27 | Slider
28 | size=3
29 |
30 |
31 | instacam-saturation-value
32 | Text
33 | Text
34 | size=1;fontSize=normal;align=center
35 |
36 |
37 | instacam-bw
38 | ToggleButton
39 | size=1
40 |
41 |
42 | instacam-bw-info
43 | Black/white
44 | Text
45 | size=null;fontSize=small;align=right
46 |
47 |
48 |
49 | Exposure compensation
50 |
51 | instacam-exposure
52 | Spinner
53 | size=2
54 |
55 |
56 | instacam-exposure-reset
57 | Reset
58 | Button
59 | size=1
60 |
61 |
62 |
63 | Selfview
64 |
65 | instacam-selfview
66 | GroupButton
67 | size=4
68 |
69 |
70 | large
71 | Large
72 |
73 |
74 | small
75 | Small
76 |
77 |
78 | off
79 | Off
80 |
81 |
82 |
83 |
84 | instacam-page
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/Instacam/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "./instacam.js",
8 | "type": "url",
9 | "id": "instacam"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": [
15 | {
16 | "payload": "./instacam.xml",
17 | "id": "instacam",
18 | "type": "url"
19 | }
20 | ]
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Instacam/settings-panel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Instacam/settings-panel.png
--------------------------------------------------------------------------------
/Join 3rd Party Meeting/JoinConferenceButton.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Join 3rd Party Meeting/JoinConferenceButton.png
--------------------------------------------------------------------------------
/Join 3rd Party Meeting/JoinConferencePanel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Join 3rd Party Meeting/JoinConferencePanel.png
--------------------------------------------------------------------------------
/Join 3rd Party Meeting/JoinMeetingGeneric.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 |
3 | // Define the domain for the meeting service you are using. Eg. @zoomcrc.com, @MSTeams.tenant, @yourbridge.com
4 | const meetingDomain = '@acme.com';
5 |
6 | const KEYBOARD_TYPES = {
7 | NUMERIC: 'Numeric',
8 | SINGLELINE: 'SingleLine',
9 | PASSWORD: 'Password',
10 | PIN: 'PIN',
11 | };
12 |
13 | const MEETING_ID = 'meetingID';
14 |
15 | /* This will be the Panel/Widget ID you are using in the UI Extension */
16 | const INROOMCONTROL_AUDIOCONTROL_PANELID = 'JoinMeetingPanel';
17 |
18 | /* Use this one if you want to limit calls to numeric only. In this example, require number to be between 3 and 10 digits. */
19 | const REGEXP_NUMERICDIALER = /^([0-9]{3,10})$/;
20 |
21 | function getMeetingID(text, value = ''){
22 |
23 | xapi.Command.UserInterface.Message.TextInput.Display({
24 | InputType: KEYBOARD_TYPES.NUMERIC,
25 | Placeholder: `No need to type ${meetingDomain}`,
26 | Title: "Join Meeting", /* Create a custom title for your meeting Input Display here */
27 | Text: text,
28 | InputText: value,
29 | SubmitText: "Join",
30 | FeedbackId: MEETING_ID,
31 | })
32 | .catch((error) => console.error(error));
33 | }
34 |
35 |
36 | /* This is the listener for the in-room control panel button that will trigger the dial panel to appear */
37 | xapi.Event.UserInterface.Extensions.Panel.Clicked.on((event) => {
38 | if(event.PanelId === INROOMCONTROL_AUDIOCONTROL_PANELID){
39 | getMeetingID("Enter the meeting id from your invite:" );
40 | }
41 | });
42 |
43 |
44 | /* Event listener for the dial pad being posted */
45 | xapi.Event.UserInterface.Message.TextInput.Response.on((event) => {
46 | switch(event.FeedbackId){
47 | case MEETING_ID:
48 | /* Change this to whatever filter you want to check for validity */
49 | const regex = REGEXP_NUMERICDIALER;
50 | const match = regex.exec(event.Text);
51 |
52 | if (match) {
53 | const meetingID = match[1];
54 | const at = meetingDomain.startsWith('@') ? '' : '@';
55 | const Number = meetingID + at + meetingDomain;
56 | console.log('Dial:', Number);
57 | xapi.Command.Dial({ Number });
58 | }
59 | else{
60 | getMeetingID("You typed in an invalid number. Please try again.", event.Text );
61 | }
62 | break;
63 | }
64 | });
--------------------------------------------------------------------------------
/Join 3rd Party Meeting/JoinMeetingPanel.xml:
--------------------------------------------------------------------------------
1 |
2 | 1.7
3 |
4 | 1
5 | callmeeting
6 | local
7 | Home
8 | Camera
9 | #07C1E4
10 | Join Conference
11 | Custom
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Join 3rd Party Meeting/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "JoinMeetingGeneric.js",
8 | "id": "JoinMeetingGeneric",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": [
15 | {
16 | "payload": "JoinMeetingPanel.xml",
17 | "id": "JoinMeetingPanel",
18 | "type": "url"
19 | }
20 | ]
21 | },
22 | "userParams": [
23 | {
24 | "id": "meetingDomain",
25 | "name": "Meeting Domain",
26 | "info": "Eg @zoomcrc.com. The url/domain for the 3rd party provider, without the actual meeting number",
27 | "type": "string",
28 | "default": "@yourbridge.com",
29 | "domain": "JoinMeetingGeneric",
30 | "required": true
31 | }
32 | ]
33 | }
34 | }
--------------------------------------------------------------------------------
/Join Zoom with DTMF Zoom Tools/Join Zoom Version 4-1-1.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Join Zoom with DTMF Zoom Tools/Join Zoom Version 4-1-1.zip
--------------------------------------------------------------------------------
/Join Zoom with DTMF Zoom Tools/joinZoom~4-1-1~Style_New.xml:
--------------------------------------------------------------------------------
1 |
2 | 1.5
3 |
4 | 3
5 | joinZoom~4-1-1~Style_New
6 | local
7 | Never
8 | Briefing
9 | Join Zoom NEW
10 | Custom
11 |
12 | Join Zoom
13 |
14 | Meeting ID
15 |
16 | joinZoom~4-1-1~Style_New~MeetingId~Text
17 | 5-40 Digit Meeting Id
18 | Text
19 | size=3;fontSize=normal;align=left
20 |
21 |
22 | joinZoom~4-1-1~Style_New~MeetingId~Enter
23 | Enter
24 | Button
25 | size=1
26 |
27 |
28 |
29 | Passcode
30 |
31 | joinZoom~4-1-1~Style_New~Passcode~Text
32 | Passcode
33 | Text
34 | size=3;fontSize=normal;align=left
35 |
36 |
37 | joinZoom~4-1-1~Style_New~Passcode~Enter
38 | Enter
39 | Button
40 | size=1
41 |
42 |
43 |
44 | Role
45 |
46 | joinZoom~4-1-1~Style_New~Role
47 | GroupButton
48 | size=4
49 |
50 |
51 | joinZoom~4-1-1~Style_New~Role~Participant
52 | Participant
53 |
54 |
55 | joinZoom~4-1-1~Style_New~Role~Host
56 | Host
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | joinZoom~4-1-1~Style_New~HostKey~Text
65 | - - - - - - - - - - - - - -
66 | Text
67 | size=4;fontSize=normal;align=center
68 |
69 |
70 |
71 |
72 |
73 | joinZoom~4-1-1~Style_New~HostKey~CallZoom
74 | Connect to Zoom
75 | Button
76 | size=4
77 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/Join Zoom with DTMF Zoom Tools/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "JoinZoom_JoinText_4-1-1.js",
8 | "id": "JoinZoom_JoinText_4-1-1",
9 | "type": "library"
10 | },
11 | {
12 | "payload": "Memory_Functions.js",
13 | "id": "Memory_Functions",
14 | "type": "library"
15 | },
16 | {
17 | "payload": "JoinZoom_Config_4-1-1.js",
18 | "id": "JoinZoom_Config_4-1-1",
19 | "type": "library"
20 | },
21 | {
22 | "payload": "JoinZoom_Main_4-1-1.js",
23 | "id": "JoinZoom_Main_4-1-1",
24 | "type": "url"
25 | }
26 | ]
27 | },
28 | "roomcontrol": {
29 | "items": [
30 | {
31 | "payload": "joinZoom~4-1-1.xml",
32 | "id": "joinZoom~4-1-1",
33 | "type": "url"
34 | },
35 | {
36 | "payload": "joinZoom~4-1-1~Style_New+Personal.xml",
37 | "id": "joinZoom~4-1-1~Style_New+Personal",
38 | "type": "url"
39 | },
40 | {
41 | "payload": "joinZoom~4-1-1~Style_New.xml",
42 | "id": "joinZoom~4-1-1~Style_New",
43 | "type": "url"
44 | },
45 | {
46 | "payload": "jzoomTools~4-1-1~Tools~Visible.xml",
47 | "id": "jzoomTools~4-1-1~Tools~Visible",
48 | "type": "url"
49 | },
50 | {
51 | "payload": "jzoomTools~4-1-1~Tools~host.xml",
52 | "id": "jzoomTools~4-1-1~Tools~host",
53 | "type": "url"
54 | },
55 | {
56 | "payload": "jzoomTools~4-1-1~Tools~participant.xml",
57 | "id": "jzoomTools~4-1-1~Tools~participant",
58 | "type": "url"
59 | }
60 | ]
61 | },
62 | "userParams": []
63 | }
64 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2018 Cisco Systems
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the "Software"), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7 | the Software, and to permit persons to whom the Software is furnished to do so,
8 | subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/Language Selector/ProvisionableApplicationPackage_language-selector.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Language Selector/ProvisionableApplicationPackage_language-selector.zip
--------------------------------------------------------------------------------
/Language Selector/language-selector.xml:
--------------------------------------------------------------------------------
1 |
2 | 1.5
3 |
4 | panel_1
5 | Home
6 | Language
7 | 1
8 | #D541D8
9 | Language
10 |
11 | Select Language
12 |
13 | Row
14 |
15 | lang
16 | GroupButton
17 | size=4;columns=1
18 |
19 |
20 | english
21 | English
22 |
23 |
24 | norwegian
25 | Norwegian
26 |
27 |
28 | arabic
29 | Arabic
30 |
31 |
32 | chinesesimplified
33 | Chinese Simplified
34 |
35 |
36 | french
37 | French
38 |
39 |
40 | hebrew
41 | Hebrew
42 |
43 |
44 | spanish
45 | Spanish
46 |
47 |
48 |
49 |
50 | hideRowNames=1
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/Language Selector/languageselector_homescreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Language Selector/languageselector_homescreen.png
--------------------------------------------------------------------------------
/Language Selector/languageselector_panel_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Language Selector/languageselector_panel_selected.png
--------------------------------------------------------------------------------
/Language Selector/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "language-selector.js",
8 | "id": "language-selector",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": [
15 | {
16 | "payload": "language-selector.xml",
17 | "id": "language-selector",
18 | "type": "url"
19 | }
20 | ]
21 | },
22 | "userParams": []
23 | }
24 | }
--------------------------------------------------------------------------------
/Launch Halfwake/LaunchHalfwake.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 |
3 | xapi.Event.UserInterface.Extensions.Panel.Clicked.on((e) => {
4 | if (e.PanelId === 'halfwake') {
5 | xapi.Command.Standby.Halfwake();
6 | }
7 | });
8 |
--------------------------------------------------------------------------------
/Launch Halfwake/README.md:
--------------------------------------------------------------------------------
1 | # Launch Halfwake
2 |
3 | A simple action button on the home screen to set the system in halfwake (signage) state
4 |
5 | Particularly useful if you have interactive digital signage on your system that you want to access easily without having to wait for the system to go to halfwake.
6 |
7 | Screenshot:
8 |
9 | 
10 |
11 |
12 | ## Requirements
13 | 1. Cisco Video endpoint (MX, SX, DX, Room series, Board series, Desk series)
14 | 2. Firmware CE9.2.1 or newer.
15 | 3. Admin user access to endpoint
16 |
--------------------------------------------------------------------------------
/Launch Halfwake/launch-halfwake.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Launch Halfwake/launch-halfwake.png
--------------------------------------------------------------------------------
/Launch Halfwake/launchhalfwake.xml:
--------------------------------------------------------------------------------
1 |
2 | 1.8
3 |
4 | 1
5 | halfwake
6 | local
7 | Home
8 | Power
9 | #07C1E4
10 | HalfWake
11 | Custom
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Launch Halfwake/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "LaunchHalfwake.js",
8 | "id": "LaunchHalfwake",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": [
15 | {
16 | "payload": "launchhalfwake.xml",
17 | "id": "halfwake",
18 | "type": "url"
19 | }
20 | ]
21 | },
22 | "userParams": []
23 | }
24 | }
--------------------------------------------------------------------------------
/Library - Send Webex Message/README.md:
--------------------------------------------------------------------------------
1 | # Send Webex Message
2 |
3 | This is a macro module that let's you send a message to a Webex user or a Webex room, using the HTTP Client command.
4 | It is a macro module, so you can import it in your own macros and use it, it does not do anything on its own.
5 |
6 | 
7 |
8 | The sender of the message will be a bot. You can create the bot user at [developer.webex.com](https://developer.webex.com) by signing in there and choosing **My Webex Apps**. Copy the token and use it like in the example below.
9 |
10 | Usage:
11 |
12 | ```
13 | import sendMessage from ‘./webex’;
14 |
15 | const yourBotToken = ‘…’; // add it
16 |
17 | sendMessage(yourBotToken, ‘tbjolset@cisco.com’, null, ‘Send markdown message to me **personally**’);
18 |
19 | sendMessage(yourBotToken, null, ‘yourRoomId’, ‘Bot must be member of any group spaces you send to’);
20 | ```
21 |
22 | You can also use all the other APIs at developer.webex.com in similar fashion to poll messages, create rooms, add members etc.
23 |
24 | **Note**: If you want to send a message to a group room, the bot must be a member of that room.
25 |
26 | ## Requirements
27 |
28 | * [xConfig HttpClient Mode](https://roomos.cisco.com/xapi/Configuration.HttpClient.Mode/) must be `On`.
29 |
--------------------------------------------------------------------------------
/Library - Send Webex Message/bot-message.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Library - Send Webex Message/bot-message.png
--------------------------------------------------------------------------------
/Library - Send Webex Message/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "webex.js",
8 | "id": "webex",
9 | "type": "library"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": []
15 | },
16 | "userParams": []
17 | }
18 | }
--------------------------------------------------------------------------------
/Library - Send Webex Message/webex.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 |
3 | const webexMsgUrl = 'https://webexapis.com/v1/messages';
4 |
5 | function sendMessage(token, toPersonEmail, roomId, markdown) {
6 | const headers = [
7 | 'Content-Type: application/json',
8 | 'Authorization: Bearer ' + token,
9 | ];
10 |
11 | const body = Object.assign({ markdown }, toPersonEmail ? { toPersonEmail } : { roomId });
12 | return xapi.Command.HttpClient.Post({ Header: headers, Url: webexMsgUrl }, JSON.stringify(body));
13 | }
14 |
15 | export default sendMessage;
16 |
--------------------------------------------------------------------------------
/Library - Weather Forecast/README.md:
--------------------------------------------------------------------------------
1 | # Library - Weather forecast
2 |
3 | Fetch global weather forecasts from the free, open Norwegian weather service at met.no No token needed.
4 |
5 | This is a macro library, so you can use it from your own extensions.
6 |
7 | Example usage:
8 |
9 | ```
10 | import xapi from 'xapi';
11 | import { getForecast } from './lib-weather';
12 |
13 | const config = {
14 | lat: "59.9114",
15 | long: "10.7579",
16 | name: "Oslo",
17 | };
18 |
19 | function showForecast(forecast) {
20 | // console.log('show', forecast);
21 | const temp = forecast[0].data.instant.details.air_temperature;
22 | const text = `Temperature: ${temp}° C`;
23 | xapi.Command.UserInterface.Message.Alert.Display({ Text: text, Duration: 5 });
24 | }
25 |
26 | getForecast(config.lat, config.long)
27 | .then(showForecast)
28 | .catch(e => console.warn('Not able to fetch weather', e));
29 | ```
30 |
31 | ## Requirements
32 |
33 | * [xConfig HttpClient Mode](https://roomos.cisco.com/xapi/Configuration.HttpClient.Mode/) must be `On`.
--------------------------------------------------------------------------------
/Library - Weather Forecast/lib-weather.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 |
3 | // eg lat=59.9114, long=10.7579 (Oslo)
4 | export function getForecast(lat, long) {
5 | const nLat = Number(lat);
6 | const nLong = Number(long);
7 | if (isNaN(nLat) || isNaN(nLong)) {
8 | throw new Error('Need to specify lat and long');
9 | }
10 | const url = `https://api.met.no/weatherapi/locationforecast/2.0/complete?lat=${nLat}&lon=${nLong}`;
11 | console.log('fetching', url);
12 |
13 | return xapi.Command.HttpClient.Get({ Url: url })
14 | .then(r => JSON.parse(r.Body))
15 | .then(res => res.properties.timeseries)
16 | }
17 |
--------------------------------------------------------------------------------
/Library - Weather Forecast/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "lib-weather.js",
8 | "id": "lib-weather",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": []
15 | },
16 | "userParams": []
17 | }
18 | }
--------------------------------------------------------------------------------
/Measure Climate/README.md:
--------------------------------------------------------------------------------
1 | # Measure office climate
2 |
3 | Measure the temperature and humidity in your office or home office, and plot it over time.
4 |
--------------------------------------------------------------------------------
/Measure Climate/climate.xml:
--------------------------------------------------------------------------------
1 |
2 | 1.8
3 |
4 | 1
5 | climate
6 | Statusbar
7 | Hvac
8 | #C233C4
9 | Climate Plot
10 | Custom
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Measure Climate/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "./storage-csv.js",
8 | "type": "library",
9 | "id": "storage-csv"
10 | },
11 | {
12 | "payload": "./measureclimate.js",
13 | "type": "url",
14 | "id": "measureclimate"
15 | }
16 | ]
17 | },
18 | "roomcontrol": {
19 | "items": [
20 | {
21 | "payload": "climate.xml",
22 | "id": "climate",
23 | "type": "url"
24 | }
25 | ]
26 | }
27 | },
28 | "profileName": "backup-tbjolset",
29 | "generatedAt": "20210526-1707"
30 | }
31 |
--------------------------------------------------------------------------------
/Measure Climate/measureclimate.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 | import storage from './storage-csv';
3 |
4 | // how often to sample data
5 | const SampleMinutes = 10;
6 | const MaxSamples = 1000;
7 | let currentData = [];
8 |
9 | function getTime() {
10 | // '2022-01-05 14:39:10.819+01:00',
11 | const date = new Date().toString();
12 | // TODO does this work for other national date settings?
13 | return date.split('.').shift();
14 | }
15 |
16 | async function measure() {
17 | const temp = Number(await xapi.Status.RoomAnalytics.AmbientTemperature.get());
18 | const humidity = Number(await xapi.Status.RoomAnalytics.RelativeHumidity.get());
19 | const sample = [getTime(), temp, humidity];
20 | currentData.push(sample);
21 | currentData = currentData.slice(-MaxSamples);
22 | await storage.save(currentData.slice(currentData));
23 | }
24 |
25 | async function showPlot() {
26 | const labels = currentData.map(i => i[0]);
27 | const temp = currentData.map(i => i[1]);
28 | const humidity = currentData.map(i => i[2]);
29 |
30 | const params = {
31 | type:'bar',
32 | data: {
33 | labels,
34 | datasets: [{ label: 'Temperature', data: temp }, { label: 'Humidiy', data: humidity }],
35 | }
36 | };
37 | const Url = 'https://quickchart.io/chart?c=' + JSON.stringify(params);
38 | // console.log(Url);
39 | xapi.Command.UserInterface.WebView.Display({ Url, Title: "Temperature" });
40 | }
41 |
42 | function onPanelClicked(e) {
43 | if (e.PanelId === 'climate') {
44 | showPlot();
45 | }
46 | }
47 |
48 | async function init() {
49 | currentData = (await storage.load()) || [];
50 | measure();
51 | setInterval(measure, SampleMinutes * 60 * 1000);
52 | xapi.Event.UserInterface.Extensions.Panel.Clicked.on(onPanelClicked);
53 | }
54 |
55 | init();
56 |
--------------------------------------------------------------------------------
/Measure Climate/storage-csv.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 |
3 | const macroName = require.main.name.replace(/^\.\//, '');
4 | const storageMacro = `${macroName}-STORAGE-CSV`;
5 |
6 | export async function load(delimiter = ';', rowDelimiter = '\n') {
7 | try {
8 | const macros = await xapi.Command.Macros.Macro.Get({
9 | Name: storageMacro,
10 | Content: true,
11 | });
12 | const content = macros.Macro[0].Content.trim();
13 | return content.split(rowDelimiter).map(row => row.trim().split(delimiter));
14 | } catch (error) {
15 | if (error.message !== 'No such macro') {
16 | throw error;
17 | }
18 | }
19 | }
20 |
21 | export async function save(rows, delimiter = ';', rowDelimiter = '\n') {
22 | const csv = rows.map(r => r.join(delimiter)).join(rowDelimiter);
23 | await xapi.Command.Macros.Macro.Save({
24 | Name: storageMacro,
25 | Overwrite: true,
26 | Transpile: false,
27 | }, csv);
28 | }
29 |
30 | export async function clear() {
31 | try {
32 | await xapi.Command.Macros.Macro.Remove({ Name: storageMacro });
33 | } catch (error) {
34 | if (!error.message.startsWith('No such macro')) {
35 | throw error;
36 | }
37 | }
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/Multi-Content Solution/MCS Deployment guide.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Multi-Content Solution/MCS Deployment guide.pdf
--------------------------------------------------------------------------------
/Multi-Content Solution/MCS_panel.xml:
--------------------------------------------------------------------------------
1 |
2 | 1.9
3 |
4 | 1
5 | mcs_panel
6 | local
7 | Statusbar
8 | Laptop
9 | #262626
10 | Share screen
11 | Custom
12 |
13 | Select content to share
14 |
15 |
16 |
17 | presentation_source
18 | GroupButton
19 | size=4;columns=2
20 |
21 |
22 | pacs_1
23 | PACS monitor 1
24 |
25 |
26 | pacs_2
27 | PACS monitor 2
28 |
29 |
30 | pc_1
31 | Clinic PC monitor 1
32 |
33 |
34 | pc_2
35 | Clinic PC monitor 2
36 |
37 |
38 |
39 |
40 | presentation_source2
41 | GroupButton
42 | size=4;columns=1
43 |
44 |
45 | 4_sources
46 | PACS + Clinic PC (4-split)
47 |
48 |
49 | laptop
50 | Laptop (HDMI-cable)
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | presentation_stop
59 | Remove presentation
60 | Button
61 | size=4
62 |
63 |
64 | hideRowNames=1
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/Multi-Content Solution/MCS_with_laptop.js:
--------------------------------------------------------------------------------
1 | //version 1.1 - updated with new syntax and optimized for RoomOS 11
2 |
3 | import xapi from 'xapi';
4 |
5 | function StartPresentation(sources){
6 | xapi.Command.Presentation.Start({PresentationSource: sources});
7 | }
8 |
9 | function StopPresentation(){
10 | xapi.Command.Presentation.Stop();
11 | xapi.Command.UserInterface.Extensions.Widget.UnsetValue({ WidgetId: 'presentation_source' });
12 | xapi.Command.UserInterface.Extensions.Widget.UnsetValue({ WidgetId: 'presentation_source2' });
13 | }
14 |
15 | xapi.Event.UserInterface.Extensions.Widget.Action.on(event => {
16 | if (event.WidgetId === 'presentation_source' && event.Type === 'released') {
17 | xapi.Command.UserInterface.Extensions.Widget.UnsetValue({ WidgetId: 'presentation_source2' });
18 | switch (event.Value){
19 | case 'pacs_1':
20 | StartPresentation(2);
21 | break;
22 | case 'pacs_2':
23 | StartPresentation(3);
24 | break;
25 | case 'pc_1':
26 | StartPresentation(5);
27 | break;
28 | case 'pc_2':
29 | StartPresentation(6);
30 | break;
31 | }
32 | }
33 | if (event.WidgetId === 'presentation_source2' && event.Type === 'released') {
34 | xapi.Command.UserInterface.Extensions.Widget.UnsetValue({ WidgetId: 'presentation_source' });
35 | switch (event.Value){
36 | case '4_sources':
37 | StartPresentation([2,3,5,6]);
38 | break;
39 | case 'laptop':
40 | StartPresentation(4);
41 | break;
42 | }
43 | }
44 | else if (event.WidgetId === 'presentation_stop' && event.Type === 'clicked' ) {
45 | StopPresentation();
46 | }
47 |
48 | //console.log(JSON.stringify(event));
49 | }
50 | );
51 |
52 | xapi.Status.Conference.Presentation.Mode.on(presentationStatus =>{
53 | if (presentationStatus === 'Off' || presentationStatus === 'Receiving'){
54 | xapi.Command.UserInterface.Extensions.Widget.UnsetValue({ WidgetId: 'presentation_source' });
55 | xapi.Command.UserInterface.Extensions.Widget.UnsetValue({ WidgetId: 'presentation_source2' });
56 | }
57 | });
58 |
59 | xapi.Status.Standby.State.on(standbyState => {
60 | if (standbyState === "Off"){
61 | StopPresentation();
62 | }});
63 |
64 | StopPresentation();
--------------------------------------------------------------------------------
/Multi-Content Solution/MDTDemoPanel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Multi-Content Solution/MDTDemoPanel.png
--------------------------------------------------------------------------------
/Multi-Content Solution/MDTDemoPanel_RoomOS10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Multi-Content Solution/MDTDemoPanel_RoomOS10.png
--------------------------------------------------------------------------------
/Multi-Content Solution/README.md:
--------------------------------------------------------------------------------
1 | # Multi-Content Solution
2 |
3 | 
4 |
5 | This is the macro and UI Extension used in the [Multi-Content Solution](https://projectworkplace.cisco.com/workspaces/special-purpose-rooms/multi-content/multi-content) in Project Workplace.
6 | The panel allow you to share either a single source, or a combination of 4.
7 |
8 | You can customize the text on the widgets using the __UI Extension editor__.
9 |
10 | **Author: Svein Terje Steffensen**
11 |
12 | ---
13 | Snapshot of Room Navigator after the "MDT Demo" button has been pressed:
14 | 
15 | ---
16 |
17 |
18 | ## Requirements
19 | 1. Cisco Room Kit Pro or Room 70S G2
20 | 2. Firmware CE9.15X or newer.
21 | 3. Admin user access to endpoint
22 |
23 | ## Usage
24 | 1. Please read the [MCS Deployment Guide](MCS%20Deployment%20guide.pdf) for an overview about how to set up and configure the Multi-Content Solution.
25 |
26 |
27 | ## Disclaimer
28 | This code is tested and found working with RoomOS 9.15.3 and RoomOS 10.6.0, but can still contain errors. Please report issues found.
29 |
30 | The macro is made available to Cisco partners and customers as a convenience to help simplify deploying the Multi-Content Solution. Cisco does not permit the use of this library in customer deployments that do not include Cisco Video Endpoint Hardware.
31 |
32 | ## Support Notice
33 | [Support](http://developer.cisco.com/site/devnet/support) for the macros is provided on a "best effort" basis via DevNet. Like any custom deployment, it is the responsibility of the partner and/or customer to ensure that the customization works correctly and this includes ensuring that the macro is properly integrated into 3rd party applications. This is particularly true if the Multi-Content Solution is customized.
34 |
35 | It is Cisco's intention to ensure macro compatibility across versions as much as possible and Cisco will make every effort to clearly document any differences in the xAPI across versions in the event that a backwards compatibility impacting change is made.
36 |
37 | Cisco Systems, Inc.
38 | [http://www.cisco.com](http://www.cisco.com)
39 | [http://developer.cisco.com/site/roomdevices](http://developer.cisco.com/site/roomdevices)
40 |
--------------------------------------------------------------------------------
/Multi-Content Solution/doctors.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Multi-Content Solution/doctors.jpg
--------------------------------------------------------------------------------
/Multi-Content Solution/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "MCS_with_laptop.js",
8 | "id": "MCS_with_laptop",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": [
15 | {
16 | "payload": "MCS_panel.xml",
17 | "id": "MCS_panel",
18 | "type": "url"
19 | }
20 | ]
21 | },
22 | "userParams": [
23 | ]
24 | }
25 | }
--------------------------------------------------------------------------------
/Philips Hue/.gitignore:
--------------------------------------------------------------------------------
1 | ui-builder.js
2 | ui.js
3 |
--------------------------------------------------------------------------------
/Philips Hue/TODO.md:
--------------------------------------------------------------------------------
1 | # TODO
2 |
3 | * Documentation on github
4 | * Add support for color temperature
5 | * Possible to enter bridge ip manually (for office)
6 |
--------------------------------------------------------------------------------
/Philips Hue/examples/incall-indicator.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 | import Hue from './hue-lib';
3 |
4 | const hue = new Hue();
5 |
6 | const inCallLamp = 6; // hue id for light to indicate in-call state
7 |
8 | async function callStateChanged() {
9 | const calls = await xapi.Status.SystemUnit.State.NumberOfActiveCalls.get();
10 | if (calls > 0) {
11 | const state = hue.Colors.red;
12 | state.on = true;
13 | hue.setLightState(inCallLamp, state);
14 | }
15 | else {
16 | hue.setLightState(inCallLamp, hue.Colors.white);
17 | }
18 | }
19 |
20 | hue.loadConfig();
21 | xapi.Status.SystemUnit.State.NumberOfActiveCalls.on(callStateChanged);
22 | callStateChanged();
23 |
--------------------------------------------------------------------------------
/Philips Hue/examples/incoming-call-blink.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 | import Hue from './hue-lib';
3 |
4 | const hue = new Hue();
5 |
6 | const lightId = 6; // hue id for light to indicate in-call state
7 | const blinks = 6;
8 |
9 | function incomingCall() {
10 | let i = 0;
11 | function blink() {
12 | if (i < blinks) {
13 | hue.blink(lightId);
14 | setTimeout(blink, 1000);
15 | }
16 | i++;
17 | }
18 |
19 | blink();
20 | }
21 |
22 | hue.loadConfig();
23 | xapi.Event.IncomingCallIndication.on(incomingCall);
24 |
--------------------------------------------------------------------------------
/Philips Hue/examples/presence-indicator.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 | import Hue from './hue-lib';
3 |
4 | const hue = new Hue();
5 |
6 | const presenceLamp = 6; // hue id for lamp to indicate people presence
7 |
8 |
9 | // requires xConfiguration RoomAnalytics PeoplePresenceDetector to be on
10 | async function presenceChanged() {
11 | const present = await xapi.Status.RoomAnalytics.PeoplePresence.get();
12 | console.log('present', present);
13 | if (present === 'Unknown') return;
14 | else {
15 | const color = present === 'Yes' ? hue.Colors.red : hue.Colors.green;
16 | hue.setLightState(presenceLamp, Object.assign({ on: true }, color));
17 | }
18 | }
19 |
20 | hue.loadConfig();
21 | xapi.Status.RoomAnalytics.PeoplePresence.on(presenceChanged);
22 | presenceChanged();
23 |
--------------------------------------------------------------------------------
/Philips Hue/examples/temperature.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 | import Hue from './hue-lib';
3 |
4 | const hue = new Hue();
5 |
6 | const temperaturePlug = 6; // hue id for device to toggle fan
7 | const temperatureThreshold = 21.5;
8 |
9 | async function pollTemperature() {
10 | try {
11 | const temp = await xapi.Status.RoomAnalytics.AmbientTemperature.get()
12 | const tooWarm = temp > temperatureThreshold;
13 | console.log(temp);
14 | hue.setLightState(temperaturePlug, { on: tooWarm });
15 | }
16 | catch(e) {} // not all devices support it
17 | }
18 |
19 | hue.loadConfig();
20 | setInterval(pollTemperature, 1000 * 5);
21 |
--------------------------------------------------------------------------------
/Philips Hue/examples/virtual-background-panel.xml:
--------------------------------------------------------------------------------
1 |
2 | 1.5
3 |
4 | 4
5 | virtual-background
6 | Home
7 | Tv
8 | #C233C4
9 | Virtual Background
10 | Custom
11 |
12 | Virtual Background
13 |
14 | Select Background
15 |
16 | virtual-background
17 | GroupButton
18 | size=4
19 |
20 |
21 | User1
22 | Fireplace
23 |
24 |
25 | User2
26 | Ocean
27 |
28 |
29 | User3
30 | Jungle
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | virtual-background-download
39 | Download images
40 | Button
41 | size=2
42 |
43 |
44 | virtual-background-delete
45 | Delete
46 | Button
47 | size=2
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/Philips Hue/examples/virtual-background.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 | import Hue from './hue-lib';
3 |
4 | const hue = new Hue();
5 |
6 | const presenceLamp = 6; // hue id for lamp to indicate people presence
7 |
8 | const images = {
9 | User1: {
10 | id: 'fireplace',
11 | url: 'https://images.unsplash.com/photo-1586997641337-63f21b02591e?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80',
12 | color: { hue: 8371, sat: 254 },
13 | },
14 | User2: {
15 | id: 'ocean',
16 | url: 'https://images.unsplash.com/photo-1468581264429-2548ef9eb732?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2670&q=80',
17 | color: { hue: 43530, sat: 226 },
18 | },
19 | User3: {
20 | id: 'jungle',
21 | url: 'https://images.unsplash.com/photo-1470058869958-2a77ade41c02?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2670&q=80',
22 | color: { hue:29251, sat: 207},
23 | },
24 | };
25 |
26 | function changeBg(id) {
27 | xapi.Command.Cameras.Background.Set({ Image: id, Mode: 'Image' });
28 | const color = images[id].color;
29 | hue.setLightState(presenceLamp, color);
30 | }
31 |
32 | async function downloadImages() {
33 | for (const id in images) {
34 | const { url } = images[id];
35 | xapi.Command.UserInterface.Message.Alert.Display({ Text: 'Downloading virtual bg: ' + id});
36 | await xapi.Command.Cameras.Background.Fetch({
37 | Url: url, Image: id,
38 | });
39 | }
40 | xapi.Command.UserInterface.Message.Alert.Display({ Text: 'Image download complete', Duration: 3 });
41 | }
42 |
43 | async function deleteImages() {
44 | for (const id in images) {
45 | await xapi.Command.Cameras.Background.Delete({ Image: id });
46 | }
47 | xapi.Command.UserInterface.Message.Alert.Display({ Text: 'Virtual images deleted', Duration: 3 });
48 | }
49 |
50 | async function init() {
51 | await hue.loadConfig();
52 | xapi.Event.UserInterface.Extensions.Widget.Action.on(e => {
53 | if (e.WidgetId === 'virtual-background' && e.Type === 'released') {
54 | changeBg(e.Value);
55 | }
56 | else if (e.WidgetId === 'virtual-background-download' && e.Type === 'clicked') {
57 | downloadImages();
58 | }
59 | else if (e.WidgetId === 'virtual-background-delete' && e.Type === 'clicked') {
60 | deleteImages();
61 | }
62 |
63 | });
64 | const light = (await hue.getLightState())[presenceLamp].state;
65 | console.log({ hue: light.hue, sat: light.sat });
66 | }
67 |
68 | init();
69 |
--------------------------------------------------------------------------------
/Philips Hue/homescreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Philips Hue/homescreen.png
--------------------------------------------------------------------------------
/Philips Hue/hue.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Philips Hue/hue.jpeg
--------------------------------------------------------------------------------
/Philips Hue/hue2.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Philips Hue/hue2.jpeg
--------------------------------------------------------------------------------
/Philips Hue/huepanel.xml:
--------------------------------------------------------------------------------
1 |
2 | 1.5
3 |
4 | 8
5 | hue-lights
6 | Home
7 | Lightbulb
8 | #CF7900
9 | Hue Setup
10 | Custom
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Philips Hue/lights-ui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Philips Hue/lights-ui.png
--------------------------------------------------------------------------------
/Philips Hue/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "https://raw.githubusercontent.com/cisco-ce/guido/main/src/ui-builder.js",
8 | "type": "library",
9 | "id": "ui-builder"
10 | },
11 | {
12 | "payload": "https://raw.githubusercontent.com/cisco-ce/guido/main/src/ui.js",
13 | "type": "library",
14 | "id": "ui"
15 | },
16 | {
17 | "payload": "./hue-lib.js",
18 | "type": "library",
19 | "id": "hue-lib"
20 | },
21 | {
22 | "payload": "./hue.js",
23 | "type": "url",
24 | "id": "hue"
25 | }
26 | ]
27 | },
28 | "roomcontrol": {
29 | "items": [
30 | {
31 | "payload": "./huepanel.xml",
32 | "id": "hue-lights",
33 | "type": "url"
34 | }
35 |
36 | ]
37 | },
38 | "userParams": [],
39 | "uninstall": [
40 | { "type": "config", "path": "FacilityService Service 4 Name", "value": "" },
41 | { "type": "panel", "id": "hue-colors" }
42 | ]
43 | },
44 | "profileName": "backup-tbjolset"
45 | }
46 |
--------------------------------------------------------------------------------
/Philips Hue/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Philips Hue/screenshot.png
--------------------------------------------------------------------------------
/Philips Hue/wizard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Philips Hue/wizard.png
--------------------------------------------------------------------------------
/Pin Code Lock/README.md:
--------------------------------------------------------------------------------
1 | # Pin Code Lock
2 | Protect your video device with a pin code lock that appears as soon as your system goes out of standby.
3 |
4 | 
5 |
6 | ## Description
7 |
8 | **NOTE: This is not a reliable security mechanism**
9 |
10 | It can typically be used a lock to prevent children from starting calls, or to hide your meeting agendas.
11 |
12 | If you happen to start the macro before having set your pin code, the default pin code is *1234*.
13 |
14 | Make sure that standby has not been disabled on your system, otherwise the pin prompt will never appear (except after reboot).
15 |
16 | ## Requirements
17 |
18 | * CE 9.1 or greater
19 | * Supported on both touch controller and devices with touch screen, such as Desk Pro and the Webex Board
20 |
21 | ## Usage
22 |
23 | * Install the macro
24 | * Set your own pin code in the macro code
25 | * Activate the macro
26 | * Set your device in standby, wake it up and enter your pin code
27 |
28 | ## Recovery
29 |
30 | If you forget your pin code, you can recover by disabling the macro from the macro editor or Control Hub.
31 |
--------------------------------------------------------------------------------
/Pin Code Lock/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "./pin-code.js",
8 | "type": "url",
9 | "id": "pin-code"
10 | }
11 | ]
12 | },
13 | "userParams": [
14 | {
15 | "id": "PIN_CODE",
16 | "name": "Your pin code",
17 | "info": "Numbers are recommended, but you can choose textual password instead",
18 | "type": "string",
19 | "default": "1234",
20 | "domain": "pin-code",
21 | "required": true
22 | }
23 | ]
24 | },
25 | "profileName": "backup-tbjolset",
26 | "generatedAt": "20210526-1707"
27 | }
28 |
--------------------------------------------------------------------------------
/Pin Code Lock/pin-code.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 |
3 | const PIN_CODE = '1234';
4 |
5 | function askForPin(text = 'Enter PIN code') {
6 | xapi.command('UserInterface Message TextInput Display', {
7 | FeedbackId: 'pin-code',
8 | Text: text,
9 | InputType: 'PIN',
10 | Placeholder: ' ',
11 | Duration: 0,
12 | });
13 | }
14 |
15 | function onResponse(code) {
16 | console.log('try pin', code);
17 | if (code === PIN_CODE)
18 | {
19 | console.log('pin correct');
20 | }
21 | else {
22 | console.log('pin failed');
23 | askForPin('Incorrect PIN, try again');
24 | }
25 | }
26 |
27 | function listenToEvents() {
28 | xapi.event.on('UserInterface Message TextInput Response', (event) => {
29 | if (event.FeedbackId === 'pin-code')
30 | onResponse(event.Text);
31 | });
32 | xapi.event.on('UserInterface Message TextInput Clear', (event) => {
33 | if (event.FeedbackId === 'pin-code') {
34 | xapi.command('Standby Halfwake');
35 | }
36 | });
37 | xapi.status.on('Standby State', (state) => {
38 | if (state === 'Off') askForPin();
39 | });
40 | }
41 |
42 | listenToEvents();
43 |
--------------------------------------------------------------------------------
/Pin Code Lock/prompt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Pin Code Lock/prompt.png
--------------------------------------------------------------------------------
/Quiet Mode/README.md:
--------------------------------------------------------------------------------
1 | # Quiet Mode
2 | Automatically (or manually) enable quiet mode after work hours, typically in your home office.
3 |
4 | 
5 |
6 | 
7 |
8 | ## Description
9 |
10 | Tired of your device waking up and glowing at home after work hours, or people calling when you are trying to relax? Quiet mode automatically changes your device after work hours by:
11 |
12 | * Set do not disturb, so you dont get incoming calls
13 | * Turn off ultrasound, so your phone or laptop doesn't connect and wake up the device
14 | * Turn off wake-on-motion, so the device doesn't wake up when you are close
15 | * Turn off sound effects
16 | * Set a custom calm wallpaper
17 |
18 | The mode can also be toggled manually by a button on the home screen, if you need to work late etc.
19 |
20 | ## Updates
21 |
22 | 30. Nov 2021:
23 |
24 | * Added support for photo frame in half wake mode
25 | * Add settings for photo frame, and button to activate half wake
26 |
27 | 13. Nov 2021:
28 |
29 | * Device was waking up in weekends, fixed
30 |
31 | 12. Nov 2021:
32 |
33 | * Possible to set time for start/end of day on device itself
34 | * Possible to turn on/off scheduled quiet mode on device itself
35 | * Your custom wallpaper is not removed if you do not choose any wallpaper
36 | * Self view is hidden when in quiet mode
37 |
38 |
39 | ## Requirements
40 |
41 | * CE 9.1 or greater
42 | * Supported on both touch controller and devices with touch screen, such as Desk Pro and the Webex Board
43 |
44 | ## Note
45 |
46 | This macro uses the `xConfig FacilityService` to store the user's preferences, so you should not install it if you are using facility service actively on your device.
47 |
--------------------------------------------------------------------------------
/Quiet Mode/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "./schedule.js",
8 | "type": "library",
9 | "id": "schedule"
10 | },
11 | {
12 | "payload": "./quietmode.js",
13 | "type": "url",
14 | "id": "quietmode"
15 | }
16 | ]
17 | },
18 | "roomcontrol": {
19 | "items": [
20 | {
21 | "payload": "./quietmode.xml",
22 | "id": "quietmode",
23 | "type": "url"
24 | }
25 | ]
26 | },
27 | "userParams": [
28 | {
29 | "id": "backgroundUrl",
30 | "name": "Wallpaper",
31 | "info": "What background would you like in quiet mode?",
32 | "type": "option",
33 | "values": {
34 | "": "(Don't change)",
35 | "https://images.unsplash.com/photo-1488543882437-49f6f714ad05?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=2676&q=80&t=river": "River",
36 | "https://images.unsplash.com/photo-1620503374956-c942862f0372?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=2670&q=80&t=abstract": "Abstract",
37 | "https://images.unsplash.com/photo-1493441883526-0ed85220dc0c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=2666&q=80&t=waves": "Waves",
38 | "https://images.unsplash.com/photo-1497436072909-60f360e1d4b1?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=2560&q=80&t=forestandwaer": "Forest and water"
39 | },
40 | "domain": "quietmode",
41 | "required": true
42 | }
43 | ],
44 | "uninstall": [
45 | { "type": "config", "path": "Standby Signage Mode", "value": "Off" },
46 | { "type": "config", "path": "FacilityService Service 5 Name", "value": "" }
47 | ]
48 |
49 | },
50 | "profileName": "backup-tbjolset",
51 | "generatedAt": "20210526-1707"
52 | }
53 |
--------------------------------------------------------------------------------
/Quiet Mode/quietmode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Quiet Mode/quietmode.png
--------------------------------------------------------------------------------
/Quiet Mode/schedule.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Library that makes it easy to schedule jobs for certain times of the day.
3 | * Time is specified in 24 h clock, like '11:30'
4 | *
5 | * todo: support am/pm
6 | */
7 |
8 | function isWeekend() {
9 | const day = new Date().getDay();
10 | return day === 0 || day === 6;
11 | }
12 |
13 | function parseTime(time) {
14 | let [hour, minute] = time.replace('.', ':').split(':').map(i => Number(i));
15 | const valid = !isNaN(hour) && !isNaN(minute) && hour >= 0 && hour < 24 && minute >= 0 && minute < 60;
16 | if (!valid) throw new Error('Not able to parse time. Expected format: HH:mm (24 hour clock)');
17 | return [hour, minute];
18 | }
19 |
20 | /**
21 | * Check if the given time is before current time
22 | * @param time Time in HH:mm format
23 | */
24 | function isBeforeNow(time) {
25 | const [h, m] = parseTime(time);
26 | const now = new Date();
27 | const hour = now.getHours();
28 | const minute = now.getMinutes();
29 | if (hour === h) return m < minute;
30 | return h < hour;
31 | }
32 |
33 | class Scheduler {
34 |
35 | /**
36 | * Schedule a one time action at a certain time. if time is in the past, schedule tomorrow
37 | */
38 | schedule(time, action) {
39 | let [hour, minute] = parseTime(time);
40 | let now = new Date();
41 | now = now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds();
42 |
43 | let difference = parseInt(hour) * 3600 + parseInt(minute) * 60 - now;
44 | if (difference <= 0) difference += 24 * 3600;
45 |
46 | const h = Math.floor(difference / 3600);
47 | const m = Math.floor((difference / 60) % 60);
48 | const s = Math.floor(difference % 60);
49 | console.log(time, ': fire in', h, 'hours', m, 'min', s, 'sec');
50 |
51 | this.timerId = setTimeout(action, difference * 1000);
52 | }
53 |
54 | scheduleDaily(time, action, onlyWeekdays = false) {
55 | this.schedule(time, () => {
56 | if (!onlyWeekdays || !isWeekend()) {
57 | action();
58 | }
59 | this.scheduleDaily(time, action, onlyWeekdays); // schedule for next day too
60 | });
61 | }
62 | cancel() {
63 | // console.log('cancel timer', this.timerId);
64 | clearTimeout(this.timerId);
65 | }
66 | }
67 |
68 | export { Scheduler, parseTime, isBeforeNow, isWeekend };
69 |
--------------------------------------------------------------------------------
/Quiet Mode/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Quiet Mode/settings.png
--------------------------------------------------------------------------------
/Remember My Volume/README.md:
--------------------------------------------------------------------------------
1 | # Remember My Volume
2 |
3 | By default, when you restart your device, the audio volume will be reset to the system's default audio setting. This macro changes the default setting to match your current volume anytime you change it, so your volume preference will always be remembered.
4 |
5 | This is particularly useful on personal devices.
6 |
--------------------------------------------------------------------------------
/Remember My Volume/RememberMyVolume.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 |
3 | xapi.Status.Audio.Volume.on(v => xapi.Config.Audio.DefaultVolume.set(parseInt(v)));
4 |
--------------------------------------------------------------------------------
/Remember My Volume/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "RememberMyVolume.js",
8 | "id": "RememberMyVolume",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "userParams": []
14 | }
15 | }
--------------------------------------------------------------------------------
/Remote Monitoring Alert/README.md:
--------------------------------------------------------------------------------
1 | # Remote Monitoring Alert
2 | Provides on-screen alerts to OSD and Touch display when remote monitoring via the admin UI is taking place. Script fires alert whenever a new `VideoSnapshotTaken` event is seen, and watches for further events typically seen when continuous refresh is toggled in the UI. Interval constant may need to be adjusted based on codec model and desired behavior.
3 |
4 | 
5 |
6 | *contributed by [Fred Nielsen](https://github.com/fredless) @ [ePlus Technology](https://www.eplus.com)*
7 |
8 |
9 | 
10 |
11 | *diagram editable via draw.io*
12 |
13 | Not extensively tested across a broad selection of code or systems, further contributions and issues welcome.
14 |
15 | 
16 |
--------------------------------------------------------------------------------
/Remote Monitoring Alert/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "remoteMonitoringAlert.js",
8 | "id": "remoteMonitoringAlert",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": []
15 | },
16 | "userParams": []
17 | }
18 | }
--------------------------------------------------------------------------------
/Remote Monitoring Alert/osdUI.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Remote Monitoring Alert/osdUI.png
--------------------------------------------------------------------------------
/Remote Monitoring Alert/remoteMonitoringAlert.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 |
3 | // Tune notice to match your deployment needs
4 | const MESSAGE = "System is being remotely monitored by an administrator";
5 |
6 | // To prevent realerts, this interval needs to be longer by some seconds than trigger fires when
7 | // continuous snapshot refresh is enabled. May vary by codec, browser and software.
8 | // Also impacts how long message remains up after monitoring is stopped.
9 | const CHECK_INTERVAL = 15;
10 |
11 | // // Gloabl state flags
12 | var alertOn = false
13 | var snapshotTrigger = false
14 |
15 | function remoteMonitorTriggered() {
16 | // Log and store snapshot event state
17 | console.log('Snapshot event triggered');
18 | snapshotTrigger = true;
19 | // Only set Alert if not already set
20 | if(!alertOn){
21 | xapi.command('UserInterface Message Alert Display', {Text:MESSAGE});
22 | alertOn = true;
23 | }
24 | }
25 |
26 | setInterval(function(){
27 | // If snapshots have discontinued since last interval, clear alert
28 | if(!snapshotTrigger && alertOn){
29 | xapi.command('UserInterface Message Alert Clear');
30 | alertOn = false;
31 | }
32 | // Reset state until next check, continuous monitoring will retrip flag when enabled
33 | else if(snapshotTrigger){
34 | snapshotTrigger = false;
35 | }
36 | }, CHECK_INTERVAL * 1000);
37 |
38 | xapi.event.on('VideoSnapshotTaken', remoteMonitorTriggered);
39 |
--------------------------------------------------------------------------------
/Remote Monitoring Alert/touchUI.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Remote Monitoring Alert/touchUI.png
--------------------------------------------------------------------------------
/Report Issue/README.md:
--------------------------------------------------------------------------------
1 | # Report Issue
2 |
3 | Web dialog that let's users create incident reports using ServiceNow.
4 |
5 | This is a branded web dialog. On a device has a Naviagor connected, the dialog opens there, otherwise it's opened on the OSD touch screen.
6 |
7 | 
8 |
9 | Branded version (theme=cisco2):
10 |
11 | 
12 |
13 |
14 | For more info and source code, see:
15 |
16 | [RoomOS samples - Report Issue](https://github.com/cisco-ce/roomos-samples/tree/main/report-issue)
17 |
18 | For a pure (non-web) macro version using native RoomOS UI dialogs, see:
19 |
20 | [wxsd-sales Report Issue](https://github.com/wxsd-sales/servicenow-macro)
--------------------------------------------------------------------------------
/Report Issue/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "https://raw.githubusercontent.com/cisco-ce/roomos-samples/main/report-issue/macro-uiextensions/report-issue.js",
8 | "type": "url",
9 | "id": "report-issue"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": [
15 | {
16 | "payload": "https://raw.githubusercontent.com/cisco-ce/roomos-samples/main/report-issue/macro-uiextensions/report-issue.xml",
17 | "id": "report_issue",
18 | "type": "url"
19 | }
20 |
21 | ]
22 | },
23 | "userParams": [
24 | {
25 | "id": "serviceNowInstance",
26 | "name": "Service Now Instance",
27 | "info": "Eg dev70811",
28 | "type": "string",
29 | "domain": "report-issue",
30 | "required": true
31 | },
32 | {
33 | "id": "serviceNowUsername",
34 | "name": "Service Now Username",
35 | "type": "string",
36 | "domain": "report-issue",
37 | "required": true
38 | },
39 | {
40 | "id": "serviceNowPassword",
41 | "name": "Service Now Password",
42 | "type": "string",
43 | "domain": "report-issue",
44 | "required": true
45 | },
46 | {
47 | "id": "botToken",
48 | "name": "Webex Bot Token",
49 | "info": "Used to send notification when issue is created",
50 | "type": "string",
51 | "domain": "report-issue",
52 | "required": false
53 | },
54 | {
55 | "id": "notify",
56 | "name": "Webex recipient",
57 | "type": "string",
58 | "domain": "report-issue",
59 | "required": false
60 | }
61 | ]
62 | },
63 | "profileName": "backup-tbjolset"
64 | }
65 |
--------------------------------------------------------------------------------
/Room Capacity Alert/RoomCapacity.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Room Capacity Alerting Macro
3 | *
4 | * Uses The Room Analytics People Count API to alert users in a room if they exceed the set capacity limits.
5 | *
6 | * Contributers:
7 | * Richard Bayes (ribayes@cisco.com)
8 | * Susanna Moneta (smoneta@cisco.com)
9 | */
10 |
11 | import xapi from 'xapi';
12 |
13 | //Variables you are able to adjust as needed for the Room Capacity and Messaging
14 | const alertTime = 20; //Time in seconds to display alert on screen and touch 10
15 |
16 |
17 | //This enables the Room Analytics required for the Macro to function properly
18 | function init() {
19 | xapi.config.set('RoomAnalytics PeopleCountOutOfCall', 'On')
20 | .catch((error) => { console.error(error); });
21 | console.log('RoomAnalytics PeopleCountOutOfCall Has been Enabled');
22 | }
23 |
24 | function alertDisplay(capacity) {
25 | const text2Display = 'Room capacity has been limited, please reduce the number of people in this room to ' + capacity + ' people';
26 |
27 | xapi.command(
28 | 'UserInterface Message Alert Display',
29 | {Title : 'Room Capacity Limit Reached',
30 | Text : (text2Display),
31 | Duration : (alertTime) }
32 | )
33 | }
34 |
35 | function checkCount(current, capacity) {
36 | if (capacity > 0 && current > capacity) {
37 | alertDisplay(capacity);
38 | console.log('*** There are too many people in the room. ', current);
39 | }
40 | }
41 |
42 | //Run init function to setup prerequisite configurations
43 | init();
44 |
45 | // Fetch current count and set feedback for change in peoplecount
46 | xapi.status
47 | .get('RoomAnalytics PeopleCount')
48 | .then((count) => {
49 | var current = count.Current;
50 | var capacity = count.Capacity;
51 |
52 | console.log(`Max occupancy for this room is: ${count.Capacity}`);
53 | console.log(`Initial people count is: ${count.Current}`);
54 |
55 | checkCount(current, capacity);
56 |
57 | // // Listen to events
58 | console.log('Adding feedback listener to: RoomAnalytics PeopleCount');
59 | xapi.status.on('RoomAnalytics PeopleCount', (count) => {
60 | if (count.Capacity) {
61 | console.log(`Updated capacity: ` + count.Capacity);
62 | capacity = count.Capacity;
63 | } else {
64 | console.log(`Updated current count: ` + count.Current);
65 | current = count.Current;
66 | }
67 | checkCount(current, capacity);
68 | })
69 | })
70 | .catch((err) => {
71 | console.log(`Failed to fetch PeopleCount, err: ${err.message}`);
72 | console.log(`Are you interacting with a Room Series? exiting...`);
73 | xapi.close();
74 | });
75 |
--------------------------------------------------------------------------------
/Room Capacity Alert/ScreenshotRoomCapacity.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Room Capacity Alert/ScreenshotRoomCapacity.jpeg
--------------------------------------------------------------------------------
/Room Capacity Alert/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "RoomCapacity.js",
8 | "id": "RoomCapacity",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": []
15 | },
16 | "userParams": [
17 | {
18 | "id": "maxPeople",
19 | "name": "Max people",
20 | "info": "The max number of people allowed in the room. For testing, set to 0",
21 | "type": "number",
22 | "default": 1,
23 | "domain": "RoomCapacity",
24 | "required": true
25 | },
26 | {
27 | "id": "alertTime",
28 | "name": "Alert duration",
29 | "info": "Number of seconds to show the alert on screen",
30 | "type": "number",
31 | "default": 20,
32 | "domain": "RoomCapacity",
33 | "required": true
34 | }
35 |
36 | ]
37 | }
38 | }
--------------------------------------------------------------------------------
/Room Cleaning and Usage/RoomCleaningAndUsage.xml:
--------------------------------------------------------------------------------
1 |
2 | 1.8
3 |
4 | 1
5 | roomCleaning
6 | Home
7 | Concierge
8 | #07C1E4
9 | Room usage
10 | Custom
11 |
12 | Room usage
13 |
14 | Last used
15 |
16 | roomCleaningTxtLastUsed
17 | -
18 | Text
19 | size=4;fontSize=normal;align=right
20 |
21 |
22 |
23 | Last cleaned
24 |
25 | roomCleaningTxtLastCleaned
26 | -
27 | Text
28 | size=4;fontSize=normal;align=right
29 |
30 |
31 |
32 | Used since cleaning
33 |
34 | roomCleaningTxtUsed
35 | -
36 | Text
37 | size=4;fontSize=normal;align=right
38 |
39 |
40 |
41 |
42 |
43 | roomCleaningButtonClean
44 | Mark as clean...
45 | Button
46 | size=4
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/Room Cleaning and Usage/images/panelStats.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Room Cleaning and Usage/images/panelStats.png
--------------------------------------------------------------------------------
/Room Cleaning and Usage/images/roomSummary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Room Cleaning and Usage/images/roomSummary.png
--------------------------------------------------------------------------------
/Room Cleaning and Usage/images/roomUsage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Room Cleaning and Usage/images/roomUsage.png
--------------------------------------------------------------------------------
/Room Cleaning and Usage/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "RoomCleaningAndUsage.js",
8 | "id": "RoomCleaningAndUsage",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": [
15 | {
16 | "payload": "RoomCleaningAndUsage.xml",
17 | "id": "RoomCleaningAndUsage",
18 | "type": "url"
19 | }
20 | ]
21 | },
22 | "userParams": [
23 | {
24 | "id": "pinCode",
25 | "name": "Pin code",
26 | "info": "Pin code number for cleaners",
27 | "type": "string",
28 | "default": "1234",
29 | "domain": "RoomCleaningAndUsage",
30 | "required": true
31 | },
32 | {
33 | "id": "maxPeople",
34 | "name": "Max people",
35 | "info": "Max number of people allowed in the room",
36 | "type": "number",
37 | "default": 1,
38 | "domain": "RoomCleaningAndUsage"
39 | }
40 | ]
41 | }
42 | }
--------------------------------------------------------------------------------
/Room Kit Pro SX80 GPIO/README.md:
--------------------------------------------------------------------------------
1 | # Room Kit PRO SX80 GPIO
2 | Start a call when user presses eg a hard button that is connected to the video device with a GPIO interface.
3 |
--------------------------------------------------------------------------------
/Room Kit Pro SX80 GPIO/Room Kit Pro SX80 GPIO.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 | const NUMBER_TO_DIAL = 'mynumber@mycompany.com';
3 |
4 | xapi.status.on('GPIO Pin', (state) => {
5 | console.log('GPIO Pin[' + state.id + '] State went to: ' + state.State);
6 | if(state.State == 'Low'){
7 | Promise.all([xapi.status.get('SystemUnit State numberOfInProgressCalls'), xapi.status.get('SystemUnit State NumberOfActiveCalls')]).then(promises => {
8 | let [numberOfInProgressCalls, numberOfActiveCalls] = promises;
9 | if(numberOfInProgressCalls == '0' && numberOfActiveCalls == '0'){
10 | xapi.command("dial", {number: NUMBER_TO_DIAL});
11 | xapi.command("UserInterface Message TextLine Display", {Text: 'Someone pressed a GPIO button. Setting up call', Duration: 3});
12 | }
13 | else{
14 | xapi.command("call disconnect");
15 | xapi.command("UserInterface Message TextLine Display", {Text: 'Someone presse the GPIO button again. Call disconnecting', Duration: 3});
16 | }
17 | });
18 | }
19 | });
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Room Kit Pro Video Compositing/roomcontrolconfig_roomkitpro_videocompositing.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Room Kit Pro Video Compositing/roomcontrolconfig_roomkitpro_videocompositing.zip
--------------------------------------------------------------------------------
/Room Metrics/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "room-metrics.js",
8 | "id": "Room Metrics",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": []
15 | },
16 | "userParams": []
17 | }
18 | }
--------------------------------------------------------------------------------
/Samsung Flip/README.md:
--------------------------------------------------------------------------------
1 | # Samsung Flip
2 |
3 | If you own a Samsung Flip and use it with a Room Kit Mini, this home screen button easily lets you switch from Webex Mode to native Flip mode.
4 |
5 | 
6 |
7 | If you need to switch back, you can do this from the native Samsung menus.
8 |
9 | 
10 |
11 | **Contact: Magnus Ohm (Cisco DTG Norway)**
12 |
--------------------------------------------------------------------------------
/Samsung Flip/flip-and-mini.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Samsung Flip/flip-and-mini.png
--------------------------------------------------------------------------------
/Samsung Flip/flipToFlip.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 |
3 |
4 | // Don't want error diagnostics for this:
5 | try {
6 | xapi.Config.Peripherals.Profile.TouchPanels.set(0);
7 | }
8 | catch(e) {
9 | console.warn('Not able to set touch panel ')
10 | }
11 |
12 | function onPanelClicked(event) {
13 | if (event.PanelId === 'webexOnFlip') {
14 | xapi.Command.Video.CEC.Output.SendInactiveSourceRequest();
15 | console.log('flip');
16 | }
17 | }
18 |
19 | xapi.Event.UserInterface.Extensions.Panel.Clicked.on(onPanelClicked);
20 |
--------------------------------------------------------------------------------
/Samsung Flip/homescreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Samsung Flip/homescreen.png
--------------------------------------------------------------------------------
/Samsung Flip/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "./flipToFlip.js",
8 | "type": "url",
9 | "id": "flipToFlip"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": [
15 | {
16 | "payload": "./flip.xml",
17 | "id": "webexOnFlip",
18 | "type": "url"
19 | }
20 | ]
21 | }
22 | },
23 | "profileName": "backup-tbjolset",
24 | "generatedAt": "20210526-1707"
25 | }
26 |
--------------------------------------------------------------------------------
/Samsung Flip/samsung-logo.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Samsung Flip/samsung-logo.jpeg
--------------------------------------------------------------------------------
/Scheduled Actions/README.md:
--------------------------------------------------------------------------------
1 | # Scheduled action
2 |
3 | This macro sample demonstrates how to have the codec automatically perform actions, like placing a call, at a specified time and day.
4 |
5 |
6 | ## Requirements
7 | 1. Cisco Video room device
8 | 2. Firmware CE9.2.1 or newer.
9 | 4. Admin user access to endpoint
10 |
11 | ## Usage
12 | 1. See the latest version of the [Cisco Webex Board, Desk, and Room Series Customization Guide](https://www.cisco.com/c/en/us/support/collaboration-endpoints/spark-room-kit-series/products-installation-and-configuration-guides-list.html) for a comprehensive introduction to UI extensions and macros; as well as step-by-step instructions on how to build and upload your code.
13 |
14 |
15 | ## Setup
16 |
17 | 1. Open the JavaScript file and change the numbers that the speed dial buttons will dial.
18 |
19 |
20 | ## Additional Information
21 |
22 | ##### xAPI
23 | Documentation for the xAPI can be found in the [Command References overview](https://www.cisco.com/c/en/us/support/collaboration-endpoints/telepresence-quick-set-series/products-command-reference-list.html).
24 |
25 | ## Disclaimer
26 | This example is only a sample and is **NOT guaranteed to be bug free and production quality**.
27 |
28 | The sample macros are meant to:
29 | - Illustrate how to use the CE Macros.
30 | - Serve as an example of the step-by-step process of building a macro using JavaScript and integration with the device xAPI
31 | - Provided as a guide for a developer to see how to initialize a macro and set up handlers for user and dialog updates.
32 |
33 | The sample macros are made available to Cisco partners and customers as a convenience to help minimize the cost of Cisco Finesse customizations. Cisco does not permit the use of this library in customer deployments that do not include Cisco Video Endpoint Hardware.
34 |
35 | ## Support Notice
36 | [Support](http://developer.cisco.com/site/devnet/support) for the macros is provided on a "best effort" basis via DevNet. Like any custom deployment, it is the responsibility of the partner and/or customer to ensure that the customization works correctly and this includes ensuring that the macro is properly integrated into 3rd party applications.
37 |
38 | It is Cisco's intention to ensure macro compatibility across versions as much as possible and Cisco will make every effort to clearly document any differences in the xAPI across versions in the event that a backwards compatibility impacting change is made.
39 |
40 | Cisco Systems, Inc.
41 | [http://www.cisco.com](http://www.cisco.com)
42 | [http://developer.cisco.com/site/roomdevices](http://developer.cisco.com/site/roomdevices)
43 |
--------------------------------------------------------------------------------
/Scheduled Actions/Scheduler.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 |
3 | const Sunday = 0, Saturday = 6;
4 |
5 |
6 | const ScheduleTime = '10:00'; // Set this to the time you want to have the device do something
7 |
8 | const SchedulerDialNumber = 'mydailymeetingnumber@mydomain.com'; //The number/URL you want the device to call at schedule
9 |
10 |
11 | function schedule(time, action) {
12 | let [alarmH, alarmM] = time.replace('.', ':').split(':');
13 | let now = new Date();
14 | now = now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds();
15 | // print("Time now:" + now);
16 | let difference = parseInt(alarmH) * 3600 + parseInt(alarmM) * 60 - now;
17 | if (difference <= 0) difference += 24 * 3600;
18 |
19 | return setTimeout(action, difference * 1000);
20 | }
21 |
22 |
23 | function dialStandup() {
24 | const weekDay = new Date().getDay();
25 | if (weekDay !== Sunday && weekDay !== Saturday) {
26 | xapi.command('Dial', { Number: SchedulerDialNumber });
27 | }
28 |
29 | schedule(ScheduleTime, dialStandup); // schedule it for the next day
30 | }
31 |
32 |
33 |
34 | schedule(ScheduleTime, dialStandup);
35 |
--------------------------------------------------------------------------------
/Scheduled Actions/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "Scheduler.js",
8 | "id": "Scheduler",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": []
15 | },
16 | "userParams": [
17 | {
18 | "id": "ScheduleTime",
19 | "name": "Time of day",
20 | "info": "Format: HH:MM (24 hour clock), the time you want the action to occur, in the local timezone",
21 | "type": "string",
22 | "default": "10:00",
23 | "domain": "Scheduler",
24 | "required": true
25 | },
26 | {
27 | "id": "SchedulerDialNumber",
28 | "name": "Number to cal",
29 | "type": "string",
30 | "default": "fireplace@ivr.vc",
31 | "domain": "Scheduler",
32 | "required": true
33 | }
34 | ]
35 | }
36 | }
--------------------------------------------------------------------------------
/Sennheiser Mute Sync/README.md:
--------------------------------------------------------------------------------
1 | # Sennheiser
2 |
3 | Ensures that the Sennheiser TCCM Ceiling Mic is synced with the mute state of the Cisco video device.
4 |
5 | 
6 |
7 | If for any reason the video device is not able to update the Sennheiser mute state, it displays a warning to users on the screen.
8 |
9 | ## Installation
10 |
11 | The integration consists of a simple library module containing the HTTP API calls necessary to talk to the ceiling mic, and a macro for calling those APIs whenever the video system mute state changes.
12 |
13 | It can be easily installed by connecting to your device from this device (tap Connect),
14 | enter your device credentials, tap Install and enter the ip/username/password for the Sennheiser API user.
15 |
16 | To install manually:
17 |
18 | * Install `sennheiser-lib.js` and `sennheiser-sync.js` on the video device
19 | * Enter the IP address, the api username and password in the `sennheiser-sync.js` file
20 | * Enable the `sennheiser-sync.js` macro
21 |
22 | Try muting / unmuting the mic (in call) - the LED on the ceiling mic should always stay in sync.
23 |
24 | ## Pre-requisites
25 |
26 | - A working setup with a Cisco video device and a Sennheiser ceiling mic
--------------------------------------------------------------------------------
/Sennheiser Mute Sync/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "./sennheiser-lib.js",
8 | "type": "library",
9 | "id": "sennheiser-lib"
10 | },
11 | {
12 | "payload": "./sennheiser-sync.js",
13 | "type": "macro",
14 | "id": "sennheiser-sync"
15 | }
16 | ]
17 | },
18 | "userParams": [
19 | {
20 | "id": "ip",
21 | "name": "IP address",
22 | "type": "string",
23 | "domain": "sennheiser-sync",
24 | "required": true
25 | },
26 | {
27 | "id": "username",
28 | "name": "API username",
29 | "type": "string",
30 | "domain": "sennheiser-sync",
31 | "required": true
32 | },
33 | {
34 | "id": "password",
35 | "name": "API password",
36 | "type": "string",
37 | "domain": "sennheiser-sync",
38 | "required": true
39 | }
40 | ]
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Sennheiser Mute Sync/sennheiser-lib.js:
--------------------------------------------------------------------------------
1 | /**
2 | * HTTP API Driver for Sennheiser ceiling mic
3 | *
4 | * Remember to enable third party api access and set username / password in the Sennheiser TCCM app
5 | * Usage:
6 | *
7 | * import Sennheiser from './sennheiser-lib'
8 | *
9 | * const mic = new Sennheiser('10.192.12.35', 'admin', 'mypassword')
10 | *
11 | * mic.setLed(on)
12 | * .catch(e => console.warn(e))
13 | *
14 | * mic.setBrightness(55)
15 | * .catch(e => console.warn(e))
16 | */
17 |
18 | import xapi from 'xapi'
19 |
20 | const LED_API_PATH = '/api/device/leds/ring'
21 |
22 | function http(url, username, password, body) {
23 | const token = btoa(`${username}:${password}`)
24 | const auth = `Authorization: Basic ${token}`
25 | const type = 'Content-Type: application/json'
26 | const options = {
27 | AllowInsecureHTTPS: true,
28 | Url: url,
29 | Header: [type, auth],
30 | ResultBody: 'PlainText'
31 | }
32 |
33 | if (!body) {
34 | return xapi.Command.HttpClient.Get(options)
35 | }
36 | return xapi.Command.HttpClient.Put(options, JSON.stringify(body))
37 | }
38 |
39 | class Driver {
40 |
41 | constructor(ip, username, password) {
42 | this.ip = ip
43 | this.username = username
44 | this.password = password
45 | }
46 |
47 | setLed(muted) {
48 | const url = 'https://' + this.ip + LED_API_PATH
49 | const body = { micOn: { color: muted ? 'Red' : 'Green' } }
50 |
51 | return http(url, this.username, this.password, body)
52 | }
53 |
54 | getStatus() {
55 | const url = 'https://' + this.ip + LED_API_PATH
56 | return http(url, this.username, this.password)
57 | }
58 |
59 | setBrightness(brightness) {
60 | const bri = Number(brightness)
61 | if (bri < 0 || bri > 5) {
62 | throw new Error('Brightness should be btw 0 and 5')
63 | }
64 | const url = 'https://' + this.ip + LED_API_PATH
65 | const body = { brightness: bri }
66 |
67 | return http(url, this.username, this.password, body)
68 | }
69 | }
70 |
71 | export default Driver
72 |
73 |
--------------------------------------------------------------------------------
/Sennheiser Mute Sync/sennheiser-sync.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Macro that ensures a Sennheiser mic shows the same mute indicator as a Cisco video device during a call.
3 | *
4 | * When the device is out of call, then mute indicator is turned off.
5 | *
6 | * If the macro at any point is unable to indicate the correct status on the Sennheiser mic,
7 | * it will display a prominent warning about this on the main video screen.
8 | */
9 | import xapi from 'xapi';
10 | import Sennheiser from './sennheiser-lib'
11 |
12 | // You must update these yourself:
13 |
14 | const ip = '169.254.1.246'
15 | const username = 'api'
16 | const password = 'xxx'
17 |
18 | const mic = new Sennheiser(ip, username, password)
19 |
20 | function showSyncWarning() {
21 | xapi.Command.UserInterface.Message.TextLine.Display({
22 | Text: '🚨 Warning: Microphone mute indicator might be wrong. 🚨',
23 | X: 5000,
24 | Y: 5000,
25 | })
26 | }
27 |
28 | function hideSyncWarning() {
29 | xapi.Command.UserInterface.Message.TextLine.Clear()
30 | }
31 |
32 | async function syncWithMute() {
33 | const onOff = await xapi.Status.Audio.Microphones.Mute.get()
34 | const muted = onOff == 'On'
35 | try {
36 | await mic.setLed(muted)
37 | hideSyncWarning()
38 | }
39 | catch(e) {
40 | console.error(e)
41 | showSyncWarning()
42 | }
43 | }
44 |
45 | async function syncWithCalls() {
46 | const numberOfCalls = await xapi.Status.SystemUnit.State.NumberOfActiveCalls.get()
47 | const brightness = (numberOfCalls > 0) ? 5 : 0
48 | try {
49 | await mic.setBrightness(brightness)
50 | hideSyncWarning()
51 | }
52 | catch(e) {
53 | console.error(e)
54 | showSyncWarning()
55 | }
56 | }
57 |
58 | function init() {
59 | // Required for the video device to talk http to the mic
60 | xapi.Config.HttpClient.Mode.set('On')
61 | xapi.Config.HttpClient.AllowInsecureHTTPS.set('True')
62 |
63 | // Sync when macro starts:
64 | syncWithMute()
65 | syncWithCalls()
66 |
67 | // Sync whenever incall or mute changes
68 | xapi.Status.Audio.Microphones.Mute.on(syncWithMute)
69 | xapi.Status.SystemUnit.State.NumberOfActiveCalls.on(syncWithCalls)
70 | }
71 |
72 | init()
73 |
--------------------------------------------------------------------------------
/Sennheiser Mute Sync/sennheiser-tcc-m.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Sennheiser Mute Sync/sennheiser-tcc-m.jpg
--------------------------------------------------------------------------------
/Settings Pro/README.md:
--------------------------------------------------------------------------------
1 | # Settings Pro
2 |
3 | Settings that you may want but don't find in the default user interface.
4 |
5 | ## Settings: Misc
6 |
7 | 
8 |
9 | * Turn off ultrasound pairing if you have multiple devices in the room and they interfer with each other
10 | * Hide work buttons (call, share etc) when device is used outside work
11 | * Speaker track demo - show how the camera is tracking your face
12 | * Disable half wake - if you are tired of the device switching btw home screen and half wake
13 |
14 |
15 | ## Settings: Audio
16 |
17 | 
18 |
19 | * Tune up the max volume for your PC input volume, for parties or demos
20 | * Share audio in call with your friends, without sharing presentation on screen (Not available on Desk series)
21 |
22 | ## Settings: Immersive share
23 |
24 | 
25 |
26 | * Fine tune the exact size and position of your immersive presenter when overlaid on top of your laptop screen
27 |
28 | ## Settings: Web
29 |
30 | 
31 |
32 | * Open any URL that you'd like without adding it as a web app, or Google a word
33 | * Prevent web data from being deleted daily (stay logged in to Gmail etc)
34 | * Clear web data if you want a fresh start
35 | * Easily turn on/off web debugging (for web developers)
--------------------------------------------------------------------------------
/Settings Pro/audio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Settings Pro/audio.png
--------------------------------------------------------------------------------
/Settings Pro/immersive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Settings Pro/immersive.png
--------------------------------------------------------------------------------
/Settings Pro/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "https://raw.githubusercontent.com/cisco-ce/guido/main/src/ui.js",
8 | "type": "library",
9 | "id": "ui"
10 | },
11 | {
12 | "payload": "./settings-pro.js",
13 | "type": "url",
14 | "id": "settings-pro"
15 | }
16 | ]
17 | },
18 | "roomcontrol": {
19 | "items": [
20 | {
21 | "payload": "./settingspro.xml",
22 | "id": "settingspro",
23 | "type": "url"
24 | }
25 |
26 | ]
27 | },
28 | "userParams": [],
29 | "uninstall": [
30 | { "type": "config", "path": "Audio Ultrasound MaxVolume", "value": "70" },
31 | { "type": "config", "path": "UserInterface Features HideAll", "value": "False" },
32 | { "type": "config", "path": "Standby Halfwake Mode", "value": "Auto" },
33 | { "type": "config", "path": "WebEngine RemoteDebugging", "value": "Off" }
34 | ]
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Settings Pro/misc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Settings Pro/misc.png
--------------------------------------------------------------------------------
/Settings Pro/web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Settings Pro/web.png
--------------------------------------------------------------------------------
/Signage Carousel/README.md:
--------------------------------------------------------------------------------
1 | # Signage Carousel
2 |
3 | Change the digital signage URL on your device periodically.
4 |
5 | 
6 |
7 | **Author: Tore Bjolseth**
8 |
9 | ## Description
10 |
11 | Instead of showing a fixed page as signage, swap between several different ones with a fixed time interval.
12 |
13 | Note: Works best with passive signage. If the signage is interactive, you might risk that the signage switches while you are in the middle of something.
14 |
15 | TIP: Use the [Office Hours settings](https://roomos.cisco.com/xapi/search?search=officehour) to run signage only during the times that people are in the office. Running signage 24/7 can reduce the life time of certain screens.
16 |
17 | ## Requirements
18 |
19 | * CE 9.1 or greater
20 | * Web engine enabled
21 |
22 | ## Usage
23 |
24 | * Install the macro
25 | * Edit the macros and add the URLs you want to show
26 |
--------------------------------------------------------------------------------
/Signage Carousel/SignageCarousel.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Changes signage between different URLs at regular interval
3 | * Eg show news, weather, company info, vacation schedules, traffic etc
4 | */
5 | import xapi from 'xapi';
6 |
7 | const urls = [
8 | 'https://random.dog/',
9 | 'https://xkcd.com/now/',
10 | 'https://cisco.com',
11 | ];
12 |
13 | let currentIndex = -1;
14 | const secondsPerUrl = 20;
15 |
16 | async function setSignage(url) {
17 | try {
18 | await xapi.Config.Standby.Signage.Url.set(url);
19 | }
20 | catch(e) {
21 | console.warn('Not able to set signage URL');
22 | }
23 | }
24 |
25 | function next() {
26 | currentIndex++;
27 | if (currentIndex >= urls.length) {
28 | currentIndex = 0;
29 | }
30 |
31 | const url = urls[currentIndex];
32 | setSignage(url);
33 | }
34 |
35 | function init() {
36 | xapi.Config.Standby.Signage.Mode.set('On');
37 | setInterval(next, secondsPerUrl * 1000);
38 | }
39 |
40 | init();
41 |
--------------------------------------------------------------------------------
/Signage Carousel/carousel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Signage Carousel/carousel.png
--------------------------------------------------------------------------------
/Signage Carousel/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "./SignageCarousel.js",
8 | "type": "url",
9 | "id": "SignageCarousel"
10 | }
11 | ]
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Smart Dual Screen Presentation/README.md:
--------------------------------------------------------------------------------
1 | # Smart(er) Dual-Screen Presentation
2 | Macro targeting multiple\dual screen systems intended to reconfigure the primary video output in certain situations when a local presentation source is shared. If the codec is NOT receiving a remote video stream on the main channel when this happens, it will reconfigure the primary monitor role to allow presentation content to also show up there. This is oft sought after functionality, particularly for systems that are most often used in lecture or training formats.
3 |
4 | *contributed by [Fred Nielsen](https://github.com/fredless) @ [ePlus Technology](https://www.eplus.com)*
5 |
6 |
7 | 
8 |
9 | *diagram editable via draw.io*
10 |
11 | Not extensively tested across a broad selection of code or systems, further contributions and issues welcome.
12 |
--------------------------------------------------------------------------------
/Smart Dual Screen Presentation/dualScreenPresentation.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 |
3 | const MONITOR_ROLES = {AUTO: 'Auto',
4 | FIRST: 'First',
5 | SECOND: 'Second',
6 | THIRD: 'Third',
7 | PRESENTATIONONLY: 'PresentationOnly',
8 | RECORDER: 'Recorder'
9 | };
10 |
11 | // Tune output connector and role states to match your deployment
12 | const NORMAL_ROLE = MONITOR_ROLES.AUTO;
13 | const OVERRIDE_ROLE = MONITOR_ROLES.PRESENTATIONONLY;
14 | const OUTPUT_CONNECTOR = 1;
15 |
16 |
17 | function log(message) {
18 | console.log(logcounter + ": " + message);
19 | logcounter += 1;
20 | }
21 |
22 | async function getVideoCallState() {
23 | let rxVideo = false;
24 | if (await (xapi.status.get('Call'))) {
25 | await (xapi.status.get('MediaChannels Call')).then(media => {
26 | let index, channel = null;
27 | for (index = 0; index < media[0].Channel.length; index++) {
28 | channel = media[0].Channel[index];
29 | if (channel.Direction == 'Incoming' &&
30 | channel.Type == 'Video' &&
31 | channel.Video.ChannelRole == 'Main' &&
32 | channel.Video.Protocol != 'Off') {
33 | rxVideo = true;
34 | }
35 | }
36 | });
37 | }
38 | return rxVideo;
39 | }
40 |
41 | function setMonitorRole(role) {
42 | xapi.config.set('Video Output Connector ' + OUTPUT_CONNECTOR + ' MonitorRole', role)
43 | .catch((error) => {console.error(error);});
44 | }
45 |
46 | async function checkPresoState(statusEvent) {
47 | logcounter = 1;
48 | log('*** execution starting');
49 | if (statusEvent.hasOwnProperty('LocalInstance')) {
50 | log('local share state change');
51 | let localPreso = statusEvent.LocalInstance[0];
52 |
53 | if (localPreso.ghost) {
54 | log('local share was stopped, set normal monitor');
55 | setMonitorRole(NORMAL_ROLE);
56 | }
57 | else if (localPreso.SendingMode) {
58 | log('local share was started');
59 |
60 | if (await (getVideoCallState())) {
61 | log('in a video call, do nothing');
62 | }
63 | else {
64 | log('not in a video call, override monitor');
65 | setMonitorRole(OVERRIDE_ROLE);
66 | }
67 | }
68 | }
69 |
70 | else {
71 | log('not a local share state change');
72 | }
73 |
74 | log('*** execution finished');
75 | }
76 |
77 | var logcounter = null;
78 | // Fire when local presentation status changes
79 | xapi.status.on('Conference Presentation', checkPresoState);
--------------------------------------------------------------------------------
/Soft Mute/README.md:
--------------------------------------------------------------------------------
1 | # Settings Pro
2 |
3 | Button on the home screen that let's you toggle microphone mute.
4 |
5 | This is nice if you want to be sure that you are muted **before** you start a call - the built-in
6 | mute buttons only work or are only available during call.
7 |
8 | The toggle button changes color and text to reflect whether the device is muted or not.
9 |
10 | 
11 | 
12 |
13 | ## Further tuning
14 |
15 | By default, the system is unmuted when you end a call. You can change that with the following config:
16 |
17 | [xConfiguration Conference MicUnmuteOnDisconnect Mode](https://roomos.cisco.com/xapi/Configuration.Conference.MicUnmuteOnDisconnect.Mode/)
--------------------------------------------------------------------------------
/Soft Mute/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "soft-mute.js",
8 | "id": "soft-mute",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": [
15 | {
16 | "payload": "soft-mute.xml",
17 | "id": "soft-mute",
18 | "type": "url"
19 | }
20 | ]
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/Soft Mute/muted.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Soft Mute/muted.png
--------------------------------------------------------------------------------
/Soft Mute/notmuted.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Soft Mute/notmuted.png
--------------------------------------------------------------------------------
/Soft Mute/soft-mute.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Let's you mute/umute yourself from the home screen, without being in a call, so you dont have to
3 | * remember muting after you have joined.
4 | *
5 | * Button changes color and text depending on mute state.
6 | *
7 | * If you want to stay muted after end of call,
8 | * see(https://roomos.cisco.com/xapi/Configuration.Conference.MicUnmuteOnDisconnect.Mode/)
9 | *
10 | * Author: Tore Bjolseth @ Cisco
11 | */
12 | import xapi from 'xapi';
13 |
14 | const PanelId = 'soft-mute'
15 | const green = '#148579'
16 | const red = '#d43b52'
17 |
18 | function toggleMute() {
19 | xapi.Command.Audio.Microphones.ToggleMute()
20 | }
21 |
22 | async function muteChanged() {
23 | const value = await xapi.Status.Audio.Microphones.Mute.get()
24 | const muted = value === 'On'
25 | const Color = muted ? red : green
26 | const Name = muted ? 'Muted' : 'Not muted'
27 |
28 | try {
29 | xapi.Command.UserInterface.Extensions.Panel.Update({ PanelId, Color, Name })
30 | }
31 | catch(e) {
32 | console.warn(e)
33 | }
34 | }
35 |
36 | function init() {
37 | xapi.Status.Audio.Microphones.Mute.on(muteChanged)
38 |
39 | // make sure it's correct when macro starts
40 | muteChanged()
41 |
42 | xapi.Event.UserInterface.Extensions.Panel.Clicked.on(e => {
43 | console.log(e)
44 | if (e.PanelId === PanelId) {
45 | toggleMute()
46 | }
47 | })
48 | }
49 |
50 | init()
51 |
52 |
--------------------------------------------------------------------------------
/Soft Mute/soft-mute.xml:
--------------------------------------------------------------------------------
1 |
2 | 1.11
3 |
4 | 1
5 | soft-mute
6 | HomeScreen
7 | Microphone
8 | #D43B52
9 | Soft mute
10 | Custom
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Speed Dials Panel/Speed Dials.js:
--------------------------------------------------------------------------------
1 | import xapi from 'xapi';
2 |
3 |
4 | xapi.event.on('UserInterface Extensions Widget Action', (event) => {
5 | var regex = /^sd_([a-zA-Z0-9@_\-\.]+)$/;
6 | if(event.Type == 'clicked'){
7 | var match = regex.exec(event.WidgetId);
8 | if (match !== null) {
9 | xapi.command("dial", {Number: match[1]});
10 | }
11 | }
12 | });
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Speed Dials Panel/SpeedDialHomescreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Speed Dials Panel/SpeedDialHomescreen.png
--------------------------------------------------------------------------------
/Speed Dials Panel/SpeedDialOpened.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Speed Dials Panel/SpeedDialOpened.png
--------------------------------------------------------------------------------
/Speed Dials Panel/homescreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Speed Dials Panel/homescreen.png
--------------------------------------------------------------------------------
/Speed Dials Panel/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "Speed Dials.js",
8 | "id": "Speed Dials",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": [
15 | {
16 | "payload": "speed-dials.xml",
17 | "id": "speed-dials",
18 | "type": "url"
19 | }
20 | ]
21 | },
22 | "userParams": []
23 | }
24 | }
--------------------------------------------------------------------------------
/Speed Dials Panel/panel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Speed Dials Panel/panel.png
--------------------------------------------------------------------------------
/Speed Dials Panel/speed-dials.xml:
--------------------------------------------------------------------------------
1 |
2 | 1.8
3 |
4 | 1
5 | speeddials
6 | local
7 | Home
8 | Handset
9 | #00D6A2
10 | Speed Dials
11 | Custom
12 |
13 | Speed Dials
14 |
15 | Row
16 |
17 | sd_fireplace@ivr.vc
18 | Call Fireplace
19 | Button
20 | size=3
21 |
22 |
23 | hideRowNames=1
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/TicTacToe/01_Home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/TicTacToe/01_Home.png
--------------------------------------------------------------------------------
/TicTacToe/02_NewGame.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/TicTacToe/02_NewGame.png
--------------------------------------------------------------------------------
/TicTacToe/03_RandomX.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/TicTacToe/03_RandomX.png
--------------------------------------------------------------------------------
/TicTacToe/04_BlankBoard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/TicTacToe/04_BlankBoard.png
--------------------------------------------------------------------------------
/TicTacToe/05_BoardFilling.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/TicTacToe/05_BoardFilling.png
--------------------------------------------------------------------------------
/TicTacToe/06_XWon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/TicTacToe/06_XWon.png
--------------------------------------------------------------------------------
/TicTacToe/07_TieGame.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/TicTacToe/07_TieGame.png
--------------------------------------------------------------------------------
/TicTacToe/08_ContinueFromLast.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/TicTacToe/08_ContinueFromLast.png
--------------------------------------------------------------------------------
/TicTacToe/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "TicTacToe.js",
8 | "id": "TicTacToe",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": []
15 | },
16 | "userParams": []
17 | }
18 | }
--------------------------------------------------------------------------------
/Timer/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Timer/.DS_Store
--------------------------------------------------------------------------------
/Timer/OSD_Timer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Timer/OSD_Timer.png
--------------------------------------------------------------------------------
/Timer/ProvisionableApplicationPackage_Timer.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Timer/ProvisionableApplicationPackage_Timer.zip
--------------------------------------------------------------------------------
/Timer/Timer.xml:
--------------------------------------------------------------------------------
1 |
2 | 1.5
3 |
4 | panel_6
5 | Statusbar
6 | Concierge
7 | 5
8 | #00D6A2
9 | Timer
10 |
11 | Timer
12 |
13 | Egg timer (minutes)
14 |
15 | timer_quick_options
16 | GroupButton
17 | size=4
18 |
19 |
20 | 5
21 | 5
22 |
23 |
24 | 10
25 | 10
26 |
27 |
28 | 15
29 | 15
30 |
31 |
32 | 20
33 | 20
34 |
35 |
36 |
37 |
38 | timer_text
39 | Text
40 | Text
41 | size=4;fontSize=small;align=right
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/Timer/Touch10_Timer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Timer/Touch10_Timer.png
--------------------------------------------------------------------------------
/Timer/Touch10_homescreen_Timer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Timer/Touch10_homescreen_Timer.png
--------------------------------------------------------------------------------
/USB Mode Version 2/USB Mode V2 Guides.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/USB Mode Version 2/USB Mode V2 Guides.zip
--------------------------------------------------------------------------------
/USB Mode Version 2/images/UsbMode_Enabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/USB Mode Version 2/images/UsbMode_Enabled.png
--------------------------------------------------------------------------------
/USB Mode Version 2/images/UsbMode_Home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/USB Mode Version 2/images/UsbMode_Home.png
--------------------------------------------------------------------------------
/USB Mode Version 2/images/icon/button_click-to-download-usb-mode-deployment-guides-and-macro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/USB Mode Version 2/images/icon/button_click-to-download-usb-mode-deployment-guides-and-macro.png
--------------------------------------------------------------------------------
/USB Mode Version 2/images/icon/button_download-deployment-guide.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/USB Mode Version 2/images/icon/button_download-deployment-guide.png
--------------------------------------------------------------------------------
/USB Mode Version 2/images/icon/green.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/USB Mode Version 2/images/icon/green.png
--------------------------------------------------------------------------------
/USB Mode Version 2/images/icon/red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/USB Mode Version 2/images/icon/red.png
--------------------------------------------------------------------------------
/USB Mode Version 2/images/icon/yellow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/USB Mode Version 2/images/icon/yellow.png
--------------------------------------------------------------------------------
/USB Mode Version 2/images/thumbnails/thumb_usb2_configuration.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/USB Mode Version 2/images/thumbnails/thumb_usb2_configuration.png
--------------------------------------------------------------------------------
/USB Mode Version 2/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "MacroVersion": "2-2-11",
4 | "profile": {
5 | "macro": {
6 | "items": [
7 | {
8 | "payload": "USB_Mode_Version_2.js",
9 | "id": "USB Mode Version 2",
10 | "type": "url"
11 | }
12 | ]
13 | },
14 | "roomcontrol": {
15 | "items": []
16 | },
17 | "userParams": [
18 | {
19 | "id": "usbWelcomePrompt",
20 | "name": "Enable USB Mode Welcome Prompt",
21 | "info": "Welcome text that guides the user every time the Enable USB Mode button is pressed",
22 | "type": "option",
23 | "values": {
24 | "true": "Enable",
25 | "false": "Disable"
26 | },
27 | "domain": "USB Mode Version 2"
28 | },
29 | {
30 | "id": "screenShare_Mode",
31 | "name": "Screenshare Mode",
32 | "info": "Standard: (Recommended) When Enable USB Mode is pressed, your default presentation source will shared; Auto: When Enable USB Mode is pressed, your active presentation continues into USB Mode",
33 | "type": "option",
34 | "values": {
35 | "standard": "Standard",
36 | "auto": "Auto"
37 | },
38 | "domain": "USB Mode Version 2"
39 | },
40 | {
41 | "id": "continuousShare_Mode",
42 | "name": "Continuous Presentation Mode",
43 | "info": "When USB mode is Disabled, do you want to stop or continue the active presentation?",
44 | "type": "option",
45 | "values": {
46 | "false": "Stop Presentation",
47 | "true": "Continue Presentation"
48 | },
49 | "domain": "USB Mode Version 2"
50 | },
51 | {
52 | "id": "sx80_Mx700_800_videoOutput_Override",
53 | "name": "Sx80/Mx800-700 Output Override",
54 | "info": "Assign the Second(HDMI) or Third(DVI) output to feed into the USB Capture Device for Sx80 based CODECs",
55 | "type": "option",
56 | "values": {
57 | "Third": "Third (DVI)",
58 | "Second": "Second (HDMI)"
59 | },
60 | "domain": "USB Mode Version 2"
61 | }
62 | ]
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Unbook Empty Room/README.md:
--------------------------------------------------------------------------------
1 | # Unbook Empty Room
2 |
3 | **Target :** Releasing the room when no one is attending.
4 |
5 | This macro use the data collected by the Cisco Video Conferencing endpoints to determine if the room is really used during a meeting. When a booking start the macro starts to listen to the metrics update events.
6 |
7 | The following metrics are used:
8 |
9 | **Active Call** -> the number of calls in progress
10 |
11 | **Presence** -> presence detection
12 |
13 | **People Count** -> the number of people counted in the room
14 |
15 | **Sound Level** -> the sound level in the room
16 |
17 | **Presentation Mode** -> the presentation mode (Off / Receiving / Sending)
18 |
19 | **Requirements**
20 |
21 | - The device must have a calendar enabled.
22 |
23 | - Also in the macro you have to set one of the 2 variables: ```const USE_PEOPLE_COUNT_ONLY``` OR ```const USE_PRESENCE_AND_COUNT``` to ```true``` to make it work
24 |
--------------------------------------------------------------------------------
/Unbook Empty Room/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "UnbookEmptyRoom.js",
8 | "id": "UnbookEmptyRoom",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "userParams": [
14 | {
15 | "id": "USE_PEOPLE_COUNT_ONLY",
16 | "name": "Don't use ultrasound detection",
17 | "info": "Check this option for open meeting spaces, rooms with big glass walls etc where ultrasound does not detect people well",
18 | "type": "bool",
19 | "domain": "UnbookEmptyRoom",
20 | "required": true
21 | }
22 | ]
23 | }
24 | }
--------------------------------------------------------------------------------
/Web App with Cache Management/README.md:
--------------------------------------------------------------------------------
1 | # Cisco Room Devices Macros - Create Web App with Authentication Controls
2 | This macro triggers all web apps to, upon exit, prompt the user to clear their login information. This is useful for running apps like whiteboarding in shared devices when logins are stored in the cache.
3 |
4 | ## Requirements
5 | 1. A Cisco Webex Board or Desk device
6 |
7 | | Minimum RoomOs Version | Webex Cloud | Webex Edge (Hybrid Cloud) | On-Premise | Microsoft Teams Room On Cisco Devices |
8 | |:-----------------------|:------------|:--------------------------|:-----------|:-----------------------------------------|
9 | | 11.13.1.16 - Board Pro | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes |
10 | | 11.6.1.5 - Desk Pro | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes |
11 |
12 | ## Usage
13 | 1. Customize the WebAppClearCache.js variables section.
14 | 2. Leverage the local web interface of the device or Control Hub to deploy and activate this macro.
15 |
16 | ## Disclaimer
17 |
18 | This solution will clear the cache to ALL web apps. This may have an impact on other solutions and was validated in a pre-production environment. This example is only a sample and is **NOT guaranteed to be bug free and production quality**.
19 |
20 | The sample macros are meant to:
21 | - Illustrate how to use the CE Macros.
22 | - Serve as an example of the step-by-step process of building a macro using JavaScript and integration with the device xAPI
23 | - Provided as a guide for a developer to see how to initialize a macro and set up handlers for user and dialog updates.
24 |
25 | The sample macros are made available to Cisco partners and customers as a convenience to help minimize the cost of customizations. Cisco does not permit the use of this library in customer deployments that do not include Cisco Video Endpoint Hardware.
26 |
27 | ## Support Notice
28 | [Support](http://developer.cisco.com/site/devnet/support) for the macros is provided on a "best effort" basis via DevNet. Like any custom deployment, it is the responsibility of the partner and/or customer to ensure that the customization works correctly and this includes ensuring that the macro is properly integrated into 3rd party applications.
29 |
30 | It is Cisco's intention to ensure macro compatibility across versions as much as possible and Cisco will make every effort to clearly document any differences in the xAPI across versions in the event that a backwards compatibility impacting change is made.
31 |
32 | Cisco Systems, Inc.
33 | [http://www.cisco.com](http://www.cisco.com)
34 | [http://developer.cisco.com/site/roomdevices](http://developer.cisco.com/site/roomdevices)
35 |
36 |
--------------------------------------------------------------------------------
/Web App with Cache Management/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "./WebAppClearCache.js",
8 | "id": "WebAppClearCache",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": []
15 | },
16 | "userParams": [
17 | {
18 | "id": "autoClear",
19 | "name": "Automatically Clear",
20 | "info": "Do you want to automatically clear login data without a prompt?",
21 | "type": "boolean",
22 | "default": false,
23 | "domain": "WebAppClearCache",
24 | "required": true
25 | },
26 | {
27 | "id": "waitTimer",
28 | "name": "Prompt Countdown",
29 | "info": "How many seconds should the prompt for clearing login display?",
30 | "type": "number",
31 | "default": 20,
32 | "domain": "WebAppClearCache",
33 | "required": true
34 | }
35 | ]
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/WebApps Manager/README.md:
--------------------------------------------------------------------------------
1 | # Cisco CE Room Devices Macros - On Device Web App Manager
2 | This macro allows simple management of ad-hoc local web apps on a device by providing a user interface to add new apps and remove existing ones.
3 |
4 | 
5 |
6 | ## Requirements
7 | 1. A Cisco Webex Board or Desk device
8 | 2. A touch controller connected to the Webex Room or Webex Board device to record cleaning events
9 | 3. Firmware CE9.13 or newer or RoomOS
10 |
11 | ## Usage
12 | 1. See the latest version of the [Cisco Webex Board, Desk, and Room Series Customization Guide](https://www.cisco.com/c/en/us/support/collaboration-endpoints/spark-room-kit-series/products-installation-and-configuration-guides-list.html) for a comprehensive introduction to UI extensions and macros; as well as step-by-step instructions on how to build and upload your code.
13 |
14 | ## Disclaimer
15 | This example is only a sample and is **NOT guaranteed to be bug free and production quality**.
16 |
17 | The sample macros are meant to:
18 | - Illustrate how to use the CE Macros.
19 | - Serve as an example of the step-by-step process of building a macro using JavaScript and integration with the device xAPI
20 | - Provided as a guide for a developer to see how to initialize a macro and set up handlers for user and dialog updates.
21 |
22 | The sample macros are made available to Cisco partners and customers as a convenience to help minimize the cost of Cisco Finesse customizations. Cisco does not permit the use of this library in customer deployments that do not include Cisco Video Endpoint Hardware.
23 |
24 | ## Support Notice
25 | [Support](http://developer.cisco.com/site/devnet/support) for the macros is provided on a "best effort" basis via DevNet. Like any custom deployment, it is the responsibility of the partner and/or customer to ensure that the customization works correctly and this includes ensuring that the macro is properly integrated into 3rd party applications.
26 |
27 | It is Cisco's intention to ensure macro compatibility across versions as much as possible and Cisco will make every effort to clearly document any differences in the xAPI across versions in the event that a backwards compatibility impacting change is made.
28 |
29 | Cisco Systems, Inc.
30 | [http://www.cisco.com](http://www.cisco.com)
31 | [http://developer.cisco.com/site/roomdevices](http://developer.cisco.com/site/roomdevices)
32 |
--------------------------------------------------------------------------------
/WebApps Manager/WebAppsManager.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/WebApps Manager/WebAppsManager.gif
--------------------------------------------------------------------------------
/WebApps Manager/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "WebApps Manager.js",
8 | "id": "WebApps Manager",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": []
15 | },
16 | "userParams": []
17 | }
18 | }
--------------------------------------------------------------------------------
/Working From Home/README.md:
--------------------------------------------------------------------------------
1 | # Working from home
2 |
3 | Automatically set your Webex status to where you are working from.
4 |
5 | 
6 |
7 | 
8 |
9 | Automatically sets your Webex status when you use a certain device, eg at home or in the office. This means you can easily tell your colleagues whether you are physically at the office or working from home that day.
10 |
11 | This is possible since a Cisco device registered to Webex will synchronize the user status.
12 |
13 | If you are lucky enough to have a personal device both at the office and at home, you can install the extension on both devices with a different message appropriate for each place.
14 |
15 | The status is automatically set if:
16 |
17 | * You are actively using the device (it's not in standby or halfwake mode for at least 5 minutes)
18 | * It's being used with the office hours you specify (eg 7:00 - 17:00)
19 | * Your current status is not the same as the one specified by your device
20 |
21 | You will be notified by a prompt on the main screen when the extension updates your status, and it will of course appear in the status text in the top left corner too.
22 |
23 | The extension will not update the status there is one already set, so not overriding eg your vacation notice, or any custom message you may set from Webex app or manually from the device..
24 |
25 | ## Prompt before setting status
26 |
27 | If someelse is also using your device, eg your spouse while you are at the office, you may want to ask before setting the status. Or just because you want to be in control. Set 'askBeforeChanging' to true in the macro or when installing.
28 |
29 | 
30 |
31 |
32 | ## Requirements
33 |
34 | * RoomOS February 2022 software or later
35 | * Webex registered
36 | * Device in personal mode
37 |
--------------------------------------------------------------------------------
/Working From Home/client-status.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Working From Home/client-status.png
--------------------------------------------------------------------------------
/Working From Home/device-screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Working From Home/device-screen.png
--------------------------------------------------------------------------------
/Working From Home/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "./wfh.js",
8 | "type": "url",
9 | "id": "wfh"
10 | }
11 | ]
12 | },
13 | "userParams": [
14 | {
15 | "id": "deviceStatus",
16 | "name": "Status text",
17 | "info": "Will be set automatically when using the device during office hours.",
18 | "type": "string",
19 | "default": "🏠 Working from home",
20 | "domain": "wfh",
21 | "required": true
22 | },
23 | {
24 | "id": "askBeforeChanging",
25 | "name": "Ask before changing status",
26 | "info": "Useful if eg your spouse is using the device when you are not.",
27 | "type": "bool",
28 | "default": false,
29 | "domain": "wfh"
30 | },
31 | {
32 | "id": "startHour",
33 | "name": "Office hour start",
34 | "type": "number",
35 | "default": 8,
36 | "domain": "wfh",
37 | "required": true
38 | },
39 | {
40 | "id": "endHour",
41 | "name": "Office hour end",
42 | "type": "number",
43 | "default": 16,
44 | "domain": "wfh",
45 | "required": true
46 | }
47 | ]
48 | },
49 | "profileName": "backup-tbjolset",
50 | "generatedAt": "20210526-1707"
51 | }
52 |
--------------------------------------------------------------------------------
/Working From Home/prompt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/Working From Home/prompt.png
--------------------------------------------------------------------------------
/make-manifest.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Script to create manifest for an extension, based on the files in the extension folder.
3 | * The manifest.json file will be put inside the extension folder, replacing any existing
4 | * manifest file there.
5 | *
6 | * It's used by eg roomos.cisco.com to install extensions easily.
7 | *
8 | * Usage:
9 | * node make_manifest
10 | *
11 | */
12 | const { readFileSync, readdirSync, fstat, writeFileSync } = require('fs');
13 | const { join, basename } = require('path');
14 |
15 | const template = require('./manifest-template.json');
16 |
17 | function endsWith(ext, file) {
18 | if (Array.isArray(ext)) {
19 | return ext.some(e => file.toLowerCase().endsWith(e.toLowerCase()));
20 | }
21 | return file.toLowerCase().endsWith(ext.toLowerCase());
22 | }
23 |
24 |
25 | function findFiles(dir, extension) {
26 | return readdirSync(dir, { withFileTypes: true })
27 | .filter(item => item.isFile() && endsWith(extension, item.name))
28 | .map(item => item.name);
29 | }
30 |
31 |
32 | function go(dir) {
33 | // console.log('make manifest', dir);
34 | const macros = findFiles(dir, '.js');
35 | const macroList = macros.map(file => {
36 | const id = basename(file, '.js');
37 | return {
38 | payload: file,
39 | id,
40 | type: 'url'
41 | }
42 | });
43 |
44 | const roomcontrol = findFiles(dir, '.xml');
45 | const roomcontrolList = roomcontrol.map(file => {
46 | const id = basename(file, '.xml');
47 | return {
48 | payload: file,
49 | id,
50 | type: 'url'
51 | }
52 | });
53 |
54 | template.profile.macro.items = macroList;
55 | template.profile.roomcontrol.items = roomcontrolList;
56 | template.profile.userParams = [];
57 |
58 | const file = join(dir, 'manifest.json');
59 | writeFileSync(file, JSON.stringify(template, null, 2));
60 | console.log('wrote', file);
61 | }
62 |
63 | function main() {
64 | const dir = process.argv[2];
65 | if (!dir) {
66 | console.log(`\nUsage: node ${process.argv[1]} \n`);
67 | process.exit(1);
68 | }
69 |
70 | go(dir);
71 | }
72 |
73 | main();
--------------------------------------------------------------------------------
/manifest-template.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "profile": {
4 | "macro": {
5 | "items": [
6 | {
7 | "payload": "mymacro.js",
8 | "id": "mymacro",
9 | "type": "url"
10 | }
11 | ]
12 | },
13 | "roomcontrol": {
14 | "items": [
15 | {
16 | "payload": "mypanel.xml",
17 | "id": "mypanel",
18 | "type": "url"
19 | }
20 | ]
21 | },
22 | "userParams": [
23 | {
24 | "id": "myVariable",
25 | "name": "My Variable",
26 | "info": "The value the user chooses will be replaced inside the js that has id equal to domain",
27 | "type": "string",
28 | "default": "foobar",
29 | "domain": "mymacro",
30 | "required": true
31 | }
32 | ]
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/roomos.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiscoDevNet/roomdevices-macros-samples/054d787a38c492535e560a4c921a731c4c959b11/roomos.png
--------------------------------------------------------------------------------
/run-macro:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * Let's you run macros easily from node (your laptop) instead of macro editor (device)
5 | * without changing any code in the macro.
6 | */
7 | const adapter = require('./universal-adapter');
8 |
9 | async function go(host, username, password, macro) {
10 | const videoDevice = { host, username, password };
11 | await adapter(videoDevice);
12 | require(macro); // macro starts with xapi available
13 | }
14 |
15 | if (process.argv.length < 6) {
16 | console.log('Run a Webex Device macro remotely from a node.js environment');
17 | console.log('Usage: ./run-macro ');
18 | console.log('\neg: ./run 10.47.31.28 admin mypwd ./mymacro.js')
19 | console.log('NOTE: macro file path is relative to the run-macro scripts folder, and must typically start with ./');
20 | process.exit(1);
21 | }
22 |
23 | const [exec, script, host, username, password, macro] = process.argv;
24 | go(host, username, password, macro);
25 |
--------------------------------------------------------------------------------
/universal-adapter.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Adapter that makes it possible to run a pure macro from an external node context instead.
3 | * Useful to develop, test and commit macros on own laptop instead of in macro editor,
4 | * then just copy/paste/export/commit & push the macro file when done.
5 | *
6 | * Macros on video device can just import the xapi object directly, but when external you need
7 | * to provide login details. Some magic here makes lets you connect to the video device with jsxapi,
8 | * then require the macro file, which will run as if it had the same xapi object as the video device
9 | *
10 | * Usage:
11 | * const adapter = require('./universal-adapter');
12 | * const videoDevice = { host: '10.0.0.99', username: 'admin', password: 'password' };
13 | * await adapter(videoDevice)
14 | * require('./mymacro'); // macro starts with xapi available
15 | *
16 | */
17 |
18 | const jsxapi = require('jsxapi');
19 | const Module = require('module');
20 |
21 | const originalRequire = Module.prototype.require;
22 |
23 | function connectXapi ({ host, username, password }) {
24 | return new Promise((resolve, reject) => {
25 | jsxapi
26 | .connect('wss://' + host, {
27 | username,
28 | password,
29 | })
30 | .on('error', e => reject(e))
31 | .on('ready', async (xapi) => {
32 | console.log('Connected to', host);
33 | resolve(xapi);
34 | });
35 | });
36 | }
37 |
38 | async function init(deviceLogin) {
39 | const xapi = await connectXapi(deviceLogin);
40 | Module.prototype.require = function() {
41 | const moduleName = arguments[0];
42 | if (moduleName === 'xapi') return xapi;
43 | return originalRequire.apply(this, arguments);
44 | }
45 | }
46 |
47 | module.exports = init;
48 |
--------------------------------------------------------------------------------