├── .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 | ![Sample In-Room Control Screenshot](Touch10_homescreen_AudioCall.png) 7 | Snapshot of Touch Controller Home Screen Panel after pressing the Audio Dialler: 8 | ![Sample In-Room Control Screenshot](Touch10_AudioCall.png) 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 | ![Screenshot](screenshot.png) 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 | ![Mute and Video Mute](mute.jpeg) -------------------------------------------------------------------------------- /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 | ![Example message](preview.png) 12 | ![Menu](menu.png) 13 | ![Confirm that you are back](confirm.png) 14 | ![Example message](toilet.jpeg) 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 | ![Big red button](https://hackster.imgix.net/uploads/cover_image/file/38674/Big_Red_Button.jpg?auto=compress&w=900&h=675&fit=min&fm=jpg) 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 | ![Sample In-Room Control Screenshot](camera_controls_touch10.png) 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 | ![End call slider](./end-call-slider.png) 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 | ![No normal end call button](./incall-view.png) 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 | ![Sample In-Room Control Screenshot](daily_reboot.png) 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 | ![Use case illustration](prompt1.png) 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 | ![Room Navigator Screenshot](prompt2.png) 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 | ![Screenshot](screenshot2.png) 11 | ![Screenshot](screenshot4.png) 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 | ![Settings panel](./settings-panel.png) 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 | ![Home screen with halfwake button](launch-halfwake.png) 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 | ![Bot message](./bot-message.png) 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 | ![Use case illustration](doctors.jpg) 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 | ![Room Navigator Screenshot](MDTDemoPanel.png) 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 | ![Sample Touch Panel Screenshot](prompt.png) 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 | ![Quiet Mode](quietmode.png) 5 | 6 | ![Settingst](settings.png) 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 | ![osdUI](osdUI.png) 5 | 6 | *contributed by [Fred Nielsen](https://github.com/fredless) @ [ePlus Technology](https://www.eplus.com)* 7 | 8 | 9 | ![Remote Monitoring Alert flow](remoteMonitoringAlert.svg) 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 | ![touchUI](touchUI.png) 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 | ![Screenshot](https://github.com/cisco-ce/roomos-samples/raw/main/report-issue/screenshots/01-whatswrong.png) 8 | 9 | Branded version (theme=cisco2): 10 | 11 | ![Screenshot](https://github.com/cisco-ce/roomos-samples/raw/main/report-issue/screenshots/branded-version.png) 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 | ![Flip and Room Kit Mini](flip-and-mini.png) 6 | 7 | If you need to switch back, you can do this from the native Samsung menus. 8 | 9 | ![Homescreen button](homescreen.png) 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 | ![Sennheiser TCC M](./sennheiser-tcc-m.jpg) 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 | ![Settings](misc.png) 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 | ![Settings](audio.png) 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 | ![Settings](immersive.png) 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 | ![Settings](web.png) 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 | ![Signage carousel illustration](carousel.png) 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 | ![dualScreenPresentation flow](dualScreenPresentation.svg) 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 | ![Unmuted](./notmuted.png) 11 | ![Muted](./muted.png) 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 | ![WebApps Manager](WebAppsManager.gif) 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 | ![Device status](./device-screen.png) 6 | 7 | ![Soft client synced](./client-status.png) 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 | ![Prompt](./prompt.png) 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 | --------------------------------------------------------------------------------