diff --git a/.github/workflows/essentialsplugins-betabuilds.yml b/.github/workflows/essentialsplugins-betabuilds.yml index 7c8c8f4..8dcd8ff 100644 --- a/.github/workflows/essentialsplugins-betabuilds.yml +++ b/.github/workflows/essentialsplugins-betabuilds.yml @@ -122,8 +122,7 @@ jobs: Write-Output " "; Write-Output "Unable to apply version to AssemblyInfo.cs files"; } - - name: add PepperDash Eng Feed - # run: nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash-engineering/index.json -username ${{ secrets.GH_PACKAGE_USER }} -password ${{ secrets.GH_PACKAGE_PASSWORD }} + - name: add PepperDash Feed run: nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username Pepperdash -password ${{ secrets.GITHUB_TOKEN }} - name: restore Nuget Packages run: nuget install .\packages.config -OutputDirectory .\packages -ExcludeVersion @@ -246,7 +245,7 @@ jobs: - name: Add nuget.exe uses: nuget/setup-nuget@v1 - name: Add Github Packages source - run: nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash-engineering/index.json -username ${{ secrets.GH_PACKAGE_USER }} -password ${{ secrets.GH_PACKAGE_PASSWORD }} + run: nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username Pepperdash -password ${{ secrets.GITHUB_TOKEN }} # Pushes to nuget, not needed unless publishing publicly #- name: Add nuget.org API Key # run: nuget setApiKey ${{ secrets.NUGET_API_KEY }} diff --git a/.github/workflows/essentialsplugins-releasebuilds.yml b/.github/workflows/essentialsplugins-releasebuilds.yml index 672d49a..1754012 100644 --- a/.github/workflows/essentialsplugins-releasebuilds.yml +++ b/.github/workflows/essentialsplugins-releasebuilds.yml @@ -77,8 +77,7 @@ jobs: Write-Output " "; Write-Output "Unable to apply version to AssemblyInfo.cs files"; } - - name: add PepperDash Eng Feed - # run: nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash-engineering/index.json -username ${{ secrets.GH_PACKAGE_USER }} -password ${{ secrets.GH_PACKAGE_PASSWORD }} + - name: add PepperDash Feed run: nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username Pepperdash -password ${{ secrets.GITHUB_TOKEN }} - name: restore Nuget Packages run: nuget install .\packages.config -OutputDirectory .\packages -ExcludeVersion @@ -191,7 +190,7 @@ jobs: - name: Add nuget.exe uses: nuget/setup-nuget@v1 - name: Add Github Packages source - run: nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash-engineering/index.json -username ${{ secrets.GH_PACKAGE_USER }} -password ${{ secrets.GH_PACKAGE_PASSWORD }} + run: nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username Pepperdash -password ${{ secrets.GITHUB_TOKEN }} # Pushes to nuget, not needed unless publishing publicly #- name: Add nuget.org API Key # run: nuget setApiKey ${{ secrets.NUGET_API_KEY }} diff --git a/README.md b/README.md index a014855..5e90902 100644 --- a/README.md +++ b/README.md @@ -1,168 +1,354 @@ -![PepperDash Logo](/images/logo_pdt_no_tagline_600.png) - -# IN DEVELOPMENT - -The plugin is currently in development - -# Acuity Fresco Lighting Plugin - -## Device Specific Information - -Update the below readme as needed to support documentation of the plugin - -### Communication Settings - -Update the communication settings as needed for the plugin being developed. - -| Setting | Value | -| ------------ | ------- | -| Baud rate | 115,200 | -| Data bits | 8 | -| Stop bits | 1 | -| Parity | None | -| Flow Control | None | -| Delimiter | "\n" | - -#### Plugin Valid Communication methods - -```c# -Com -``` - -### Plugin Configuration Object - -Update the configuration object as needed for the plugin being developed. - -```json -{ - "devices": [ - { - "key": "lights-1", - "name": "Acuity Fresco Lighting Scenes", - "type": "acuityfresco", - "group": "pluginDevices", - "properties": { - "control": { - "method": "com", - "controlPortDevKey": "processor", - "controlPortNumber": 1, - "comParams": { - "baudRate": 115200, - "dataBits": 8, - "stopBits": 1, - "parity": "None", - "protocol": "RS232", - "hardwareHandshake": "None", - "softwareHandshake": "None" - } - }, - "pollTimeMs": 30000, - "warningTimeoutMs": 180000, - "errorTimeoutMs": 300000, - "scenes": [ - { - "name": "Scene 1", - "id": 1, - "roomId": "A", - "level": 100 - }, - { - "name": "Scene 2", - "id": 5, - "roomId": "B", - "level": 50 - }, - { - "name": "Scene 3", - "id": 36, - "roomId": "X", - "level": 0 - } - ] - } - } - ] -} -``` - -### Plugin Bridge Configuration Object - -Update the bridge configuration object as needed for the plugin being developed. - -```json -{ - "devices": [ - { - "key": "lights-1-bridge", - "uid": 11, - "name": "Example Plugin Bridge", - "group": "api", - "type": "eiscApiAdvanced", - "properties": { - "control": { - "tcpSshProperties": { - "address": "127.0.0.2", - "port": 0 - }, - "ipid": "B1" - }, - "devices": [ - { - "deviceKey": "lights-1", - "joinStart": 1 - } - ] - } - } - ] -} -``` - -### SiMPL EISC Bridge Map - -#### Digitals - -| dig-o (Input/Triggers) | I/O | dig-i (Feedback) | -| ---------------------- | --- | ------------------------- | -| | 1 | Is Online | -| Scene 1 Select | 11 | Scene 1 Feedback | -| Scene 2 Select | 12 | Scene 2 Feedback | -| Scene 3 Select | 13 | Scene 3 Feedback | -| Scene 4 Select | 14 | Scene 4 Feedback | -| Scene 5 Select | 15 | Scene 5 Feedback | -| Scene 6 Select | 16 | Scene 6 Feedback | -| Scene 7 Select | 17 | Scene 7 Feedback | -| Scene 8 Select | 18 | Scene 8 Feedback | -| Scene 9 Select | 19 | Scene 9 Feedback | -| Scene 10 Select | 20 | Scene 10 Feedback | -| | 41 | Scene 1 Visible Feedback | -| | 42 | Scene 2 Visible Feedback | -| | 43 | Scene 3 Visible Feedback | -| | 44 | Scene 4 Visible Feedback | -| | 45 | Scene 5 Visible Feedback | -| | 46 | Scene 6 Visible Feedback | -| | 47 | Scene 7 Visible Feedback | -| | 48 | Scene 8 Visible Feedback | -| | 49 | Scene 9 Visible Feedback | -| | 50 | Scene 10 Visible Feedback | - -#### Analogs - -| an_o (Input/Triggers) | I/O | an_i (Feedback) | -| --------------------- | --- | -------------------- | -| Select Scene by Index | 1 | Scene Index Feedback | - -#### Serials - -| serial-o (Input/Triggers) | I/O | serial-i (Feedback) | -| ----------------------------- | --- | ------------------- | -| Integration ID Set (NOT USED) | 1 | | - -### DEVJSON Commands - -```plaintext -devjson:1 {"deviceKey":"lights-1", "methodName":"GetScenes", "params":[]} - -devjson:1 {"deviceKey":"lights-1", "methodName":"ResetDebugLevels", "params":[]} -devjson:1 {"deviceKey":"lights-1", "methodName":"SetDebugLevels", "params":[{level 0-2}]} -``` +![PepperDash Logo](/images/logo_pdt_no_tagline_600.png) + +# Acuity Fresco Lighting Plugin + +## Device Specific Information + +Update the below readme as needed to support documentation of the plugin + +### Communication Settings + +Update the communication settings as needed for the plugin being developed. + +| Setting | Value | +| ------------ | ------- | +| Baud rate | 115,200 | +| Data bits | 8 | +| Stop bits | 1 | +| Parity | None | +| Flow Control | None | +| Delimiter | "\n" | + +#### Plugin Valid Communication methods + +```c# +Com +``` + +#### Example API Commands + +API Command Structure + +```c# +'scene {sceneId} {level} 0 {roomId}' +``` + +`sceneId` valid values are 0-36, `sceneId` 0 represents off +`level` valid values are 0-100, values < 100 will be applied relative to the current lighting level value +`roomId` valid values are A-X, `roomId`'s can be concatenated, for example `ABC` is avalid room ID for combined spaces + +Example Command + +```c# +'scene 3 100 0 A' // select scene 3, 100%, in Room with ID 'A' +'scene 8 50 0 AB' // select scene 8, 50% (relative to current light level), in Rooms with ID 'A' & 'B' +``` + +### Plugin Configuration Object + +Update the configuration object as needed for the plugin being developed. + +```json +{ + "devices": [ + { + "key": "lights1", + "name": "Acuity Fresco Lighting Scenes", + "type": "acuityfresco", + "group": "pluginDevices", + "properties": { + "control": { + "method": "com", + "controlPortDevKey": "processor", + "controlPortNumber": 1, + "comParams": { + "baudRate": 115200, + "dataBits": 8, + "stopBits": 1, + "parity": "None", + "protocol": "RS232", + "hardwareHandshake": "None", + "softwareHandshake": "None" + } + }, + "pollTimeMs": 30000, + "warningTimeoutMs": 180000, + "errorTimeoutMs": 300000, + "scenes": [ + { + "name": "Scene 1", + "id": 1, + "roomId": "A", + "level": 100 + }, + { + "name": "Scene 2", + "id": 5, + "roomId": "B", + "level": 50 + }, + { + "name": "Scene 3", + "id": 36, + "roomId": "X", + "level": 0 + } + ] + } + } + ] +} +``` + +### Plugin Bridge Configuration Object + +Update the bridge configuration object as needed for the plugin being developed. + +```json +{ + "devices": [ + { + "key": "lights1-bridge", + "uid": 11, + "name": "Example Plugin Bridge", + "group": "api", + "type": "eiscApiAdvanced", + "properties": { + "control": { + "tcpSshProperties": { + "address": "127.0.0.2", + "port": 0 + }, + "ipid": "B1" + }, + "devices": [ + { + "deviceKey": "lights1", + "joinStart": 1 + } + ] + } + } + ] +} +``` + +### SiMPL EISC Bridge Map + +#### Digitals + +| dig-o (Input/Triggers) | I/O | dig-i (Feedback) | +| ---------------------- | --- | ------------------------- | +| | 1 | Is Online | +| Scene 1 Select | 11 | Scene 1 Feedback | +| Scene 2 Select | 12 | Scene 2 Feedback | +| Scene 3 Select | 13 | Scene 3 Feedback | +| Scene 4 Select | 14 | Scene 4 Feedback | +| Scene 5 Select | 15 | Scene 5 Feedback | +| Scene 6 Select | 16 | Scene 6 Feedback | +| Scene 7 Select | 17 | Scene 7 Feedback | +| Scene 8 Select | 18 | Scene 8 Feedback | +| Scene 9 Select | 19 | Scene 9 Feedback | +| Scene 10 Select | 20 | Scene 10 Feedback | +| | 41 | Scene 1 Visible Feedback | +| | 42 | Scene 2 Visible Feedback | +| | 43 | Scene 3 Visible Feedback | +| | 44 | Scene 4 Visible Feedback | +| | 45 | Scene 5 Visible Feedback | +| | 46 | Scene 6 Visible Feedback | +| | 47 | Scene 7 Visible Feedback | +| | 48 | Scene 8 Visible Feedback | +| | 49 | Scene 9 Visible Feedback | +| | 50 | Scene 10 Visible Feedback | + +#### Analogs + +| an_o (Input/Triggers) | I/O | an_i (Feedback) | +| --------------------- | --- | ------------------------------------- | +| | | Communication Monitor Status Feedback | +| | | Socket Status Feedback | +| Select Scene by Index | 10 | Scene Index Feedback | + +#### Serials + +| serial-o (Input/Triggers) | I/O | serial-i (Feedback) | +| ------------------------- | --- | ------------------- | +| | 1 | Device Name | + +### DEVJSON Commands + +```plaintext +devjson:1 {"deviceKey":"lights-1", "methodName":"GetScenes", "params":[]} + +devjson:1 {"deviceKey":"lights-1", "methodName":"ResetDebugLevels", "params":[]} +devjson:1 {"deviceKey":"lights-1", "methodName":"SetDebugLevels", "params":[{level 0-2}]} +``` +======= +![PepperDash Logo](/images/logo_pdt_no_tagline_600.png) + +# IN DEVELOPMENT + +The plugin is currently in development + +# Acuity Fresco Lighting Plugin + +## Device Specific Information + +Update the below readme as needed to support documentation of the plugin + +### Communication Settings + +Update the communication settings as needed for the plugin being developed. + +| Setting | Value | +| ------------ | ------- | +| Baud rate | 115,200 | +| Data bits | 8 | +| Stop bits | 1 | +| Parity | None | +| Flow Control | None | +| Delimiter | "\n" | + +#### Plugin Valid Communication methods + +```c# +Com +``` + +### Plugin Configuration Object + +Update the configuration object as needed for the plugin being developed. + +```json +{ + "devices": [ + { + "key": "lights-1", + "name": "Acuity Fresco Lighting Scenes", + "type": "acuityfresco", + "group": "pluginDevices", + "properties": { + "control": { + "method": "com", + "controlPortDevKey": "processor", + "controlPortNumber": 1, + "comParams": { + "baudRate": 115200, + "dataBits": 8, + "stopBits": 1, + "parity": "None", + "protocol": "RS232", + "hardwareHandshake": "None", + "softwareHandshake": "None" + } + }, + "pollTimeMs": 30000, + "warningTimeoutMs": 180000, + "errorTimeoutMs": 300000, + "scenes": [ + { + "name": "Scene 1", + "id": 1, + "roomId": "A", + "level": 100 + }, + { + "name": "Scene 2", + "id": 5, + "roomId": "B", + "level": 50 + }, + { + "name": "Scene 3", + "id": 36, + "roomId": "X", + "level": 0 + } + ] + } + } + ] +} +``` + +### Plugin Bridge Configuration Object + +Update the bridge configuration object as needed for the plugin being developed. + +```json +{ + "devices": [ + { + "key": "lights-1-bridge", + "uid": 11, + "name": "Example Plugin Bridge", + "group": "api", + "type": "eiscApiAdvanced", + "properties": { + "control": { + "tcpSshProperties": { + "address": "127.0.0.2", + "port": 0 + }, + "ipid": "B1" + }, + "devices": [ + { + "deviceKey": "lights-1", + "joinStart": 1 + } + ] + } + } + ] +} +``` + +### SiMPL EISC Bridge Map + +#### Digitals + +| dig-o (Input/Triggers) | I/O | dig-i (Feedback) | +| ---------------------- | --- | ------------------------- | +| | 1 | Is Online | +| Scene 1 Select | 11 | Scene 1 Feedback | +| Scene 2 Select | 12 | Scene 2 Feedback | +| Scene 3 Select | 13 | Scene 3 Feedback | +| Scene 4 Select | 14 | Scene 4 Feedback | +| Scene 5 Select | 15 | Scene 5 Feedback | +| Scene 6 Select | 16 | Scene 6 Feedback | +| Scene 7 Select | 17 | Scene 7 Feedback | +| Scene 8 Select | 18 | Scene 8 Feedback | +| Scene 9 Select | 19 | Scene 9 Feedback | +| Scene 10 Select | 20 | Scene 10 Feedback | +| | 41 | Scene 1 Visible Feedback | +| | 42 | Scene 2 Visible Feedback | +| | 43 | Scene 3 Visible Feedback | +| | 44 | Scene 4 Visible Feedback | +| | 45 | Scene 5 Visible Feedback | +| | 46 | Scene 6 Visible Feedback | +| | 47 | Scene 7 Visible Feedback | +| | 48 | Scene 8 Visible Feedback | +| | 49 | Scene 9 Visible Feedback | +| | 50 | Scene 10 Visible Feedback | + +#### Analogs + +| an_o (Input/Triggers) | I/O | an_i (Feedback) | +| --------------------- | --- | -------------------- | +| Select Scene by Index | 1 | Scene Index Feedback | + +#### Serials + +| serial-o (Input/Triggers) | I/O | serial-i (Feedback) | +| ----------------------------- | --- | ------------------- | +| Integration ID Set (NOT USED) | 1 | | + +### DEVJSON Commands + +```plaintext +devjson:1 {"deviceKey":"lights-1", "methodName":"GetScenes", "params":[]} + +devjson:1 {"deviceKey":"lights-1", "methodName":"ResetDebugLevels", "params":[]} +devjson:1 {"deviceKey":"lights-1", "methodName":"SetDebugLevels", "params":[{level 0-2}]} +``` diff --git a/configurationFile.json b/configurationFile.json new file mode 100644 index 0000000..119d011 --- /dev/null +++ b/configurationFile.json @@ -0,0 +1,96 @@ +{ + "system_url": "", + "template": { + "info": { + "comment": "", + "requiredControlSofwareVersion": "", + "systemType": "huddle", + "lastModifiedDate": "2018-07-09T20:00:47.873Z", + "lastUid": 23, + "processorType": "rmc3" + }, + "devices": [ + { + "key": "processor", + "group": "processor", + "uid": 0, + "supportsCompliance": true, + "type": "rmc3", + "properties": {}, + "name": "RMC3" + }, + { + "key": "lights-1", + "name": "Acuity Fresco Lighting Scenes", + "type": "acuityfresco", + "group": "pluginDevices", + "properties": { + "control": { + "method": "com", + "controlPortDevKey": "processor", + "controlPortNumber": 1, + "comParams": { + "baudRate": 115200, + "dataBits": 8, + "stopBits": 1, + "parity": "None", + "protocol": "RS232", + "hardwareHandshake": "None", + "softwareHandshake": "None" + } + }, + "pollTimeMs": 30000, + "warningTimeoutMs": 180000, + "errorTimeoutMs": 300000, + "scenes": [ + { + "name": "Scene 1", + "id": 1, + "roomId": "A", + "level": 100 + }, + { + "name": "Scene 2", + "id": 5, + "roomId": "B", + "level": 50 + }, + { + "name": "Scene 3", + "id": 36, + "roomId": "X", + "level": 0 + } + ] + } + }, + { + "key": "lights-1-bridge", + "uid": 11, + "name": "Example Plugin Bridge", + "group": "api", + "type": "eiscApiAdvanced", + "properties": { + "control": { + "tcpSshProperties": { + "address": "127.0.0.2", + "port": 0 + }, + "ipid": "B1" + }, + "devices": [ + { + "deviceKey": "lights-1", + "joinStart": 1 + } + ] + } + } + ], + "rooms": [], + "sourceLists": {}, + "tieLines": [] + }, + "template_url": "", + "system": {} +} \ No newline at end of file diff --git a/fcs-avi-interface-commands.pdf b/fcs-avi-interface-commands.pdf new file mode 100644 index 0000000..429740c Binary files /dev/null and b/fcs-avi-interface-commands.pdf differ diff --git a/packages.config b/packages.config index 5552596..d64fd91 100644 --- a/packages.config +++ b/packages.config @@ -1,3 +1,3 @@ - - + + \ No newline at end of file diff --git a/src/AcuityFrescoBridgeJoinMap.cs b/src/AcuityFrescoBridgeJoinMap.cs new file mode 100644 index 0000000..f8acc4a --- /dev/null +++ b/src/AcuityFrescoBridgeJoinMap.cs @@ -0,0 +1,166 @@ +using PepperDash.Essentials.Core; + +namespace PepperDashPluginAcuityFresco +{ + /// + /// Plugin device Bridge Join Map + /// + public class AcuityFrescoBridgeJoinMap : JoinMapBaseAdvanced + { + /* + GenericLightingJoinMap + + [JoinName("IsOnline")] + * JoinNumber = 1 + * JoinSpan = 1 + * JoinCapabilities = eJoinCapabilities.ToSIMPL + * JoinType = eJoinType.Digital + + [JoinName("SelectScene")] + * JoinNumber = 1 + * JoinSpan = 1 + * JoinCapabilities = eJoinCapabilities.FromSIMPL + * JoinType = eJoinType.Digital + + [JoinName("SelectSceneDirect")] + * JoinNumber = 11 + * JoinSpan = 10 + * JoinCapabilities = eJoinCapabilities.ToFromSIMPL + * JoinType = eJoinType.DigitalSerial + + [JoinName("ButtonVisibility")] + * JoinNumber = 41 + * JoinSpan = 10 + * JoinCapabilities = eJoinCapabilities.ToSIMPL + * JoinType = eJoinType.Digital + + ** NOT USED ** + [JoinName("IntegrationIdSet")] + * JoinNumber = 1 + * JoinSpan = 1 + * JoinCapabilities = eJoinCapabilities.FromSIMPL + * JoinType = eJoinType.Serial + */ + + #region Digital + + [JoinName("IsOnline")] + public JoinDataComplete IsOnline = new JoinDataComplete( + new JoinData + { + JoinNumber = 1, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Device is online feedback", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("SceneSelectDirect")] + public JoinDataComplete SceneSelectDirect = new JoinDataComplete( + new JoinData + { + JoinNumber = 11, + JoinSpan = 10 + }, + new JoinMetadata + { + Description = "Device direct scene select, feedback, and names", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.DigitalSerial + }); + + [JoinName("SceneButtonVisibility")] + public JoinDataComplete SceneButtonVisibility = new JoinDataComplete( + new JoinData + { + JoinNumber = 41, + JoinSpan = 10 + }, + new JoinMetadata + { + Description = "Device scene button visibility feedback", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + #endregion + + + #region Analog + + [JoinName("CommunicationMonitorStatus")] + public JoinDataComplete CommunicationMonitorStatus = new JoinDataComplete( + new JoinData + { + JoinNumber = 1, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Device communication monitor status feedback", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Analog + }); + + [JoinName("SocketStatus")] + public JoinDataComplete SocketStatus = new JoinDataComplete( + new JoinData + { + JoinNumber = 2, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Device socket status feedback", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Analog + }); + + [JoinName("SceneSelect")] + public JoinDataComplete SceneSelect = new JoinDataComplete( + new JoinData + { + JoinNumber = 10, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Device scene select by index with feedback", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Analog + }); + + #endregion + + + #region Serial + + [JoinName("DeviceName")] + public JoinDataComplete DeviceName = new JoinDataComplete( + new JoinData + { + JoinNumber = 1, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Device Name", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + #endregion + + /// + /// Plugin device BridgeJoinMap constructor + /// + /// This will be the join it starts on the EISC bridge + public AcuityFrescoBridgeJoinMap(uint joinStart) + : base(joinStart, typeof(AcuityFrescoBridgeJoinMap)) + { + } + } +} diff --git a/src/AcuityFrescoDevice.cs b/src/AcuityFrescoDevice.cs new file mode 100644 index 0000000..1f3ed09 --- /dev/null +++ b/src/AcuityFrescoDevice.cs @@ -0,0 +1,516 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using Crestron.SimplSharpPro.DeviceSupport; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Bridges; +using PepperDash.Essentials.Core.Queues; + + +namespace PepperDashPluginAcuityFresco +{ + /// + /// Plugin device + /// + public class AcuityFrescoDevice : EssentialsBridgeableDevice + { + private const string CommsDelimiter = "\r"; + private readonly IBasicCommunication _comms; + private readonly GenericCommunicationMonitor _commsMonitor; + private GenericQueue _commsRxQueue; + + /// + /// Communication status monitor + /// + public StatusMonitorBase CommunicationMonitor { get { return _commsMonitor; } } + + /// + /// Online feedback + /// + public BoolFeedback OnlineFeedback { get; private set; } + + /// + /// Communication monitor feedback + /// + public IntFeedback CommunicationMonitorFeedback { get; private set; } + + /// + /// Socket status feedback + /// + public IntFeedback SocketStatusFeedback { get; private set; } + + /// + /// List of configured scenes + /// + public readonly List Scenes; + + private uint _activeScene; + + /// + /// Stores the active scene index + /// + public uint ActiveScene + { + get { return _activeScene; } + private set + { + if (_activeScene == value) return; + _activeScene = value; + + SceneSelectFeedback.FireUpdate(); + + var index = 0; + foreach (var scene in Scenes) + { + scene.IsActive = (index == _activeScene); + SceneSelectDirectFeebacks[index].FireUpdate(); + index++; + } + } + } + + /// + /// Scene select direct feedback + /// + public Dictionary SceneSelectDirectFeebacks { get; private set; } + + /// + /// Scene select index feedback + /// + public IntFeedback SceneSelectFeedback { get; private set; } + + + /// + /// Plugin device constructor + /// + /// device key + /// device name + /// device configuration object + /// device communication as IBasicCommunication + /// + /// + public AcuityFrescoDevice(string key, string name, AcuityFrescoPropertiesConfig config, IBasicCommunication comms) + : base(key, name) + { + Debug.Console(TraceLevel, this, "Constructing new {0} instance", name); + + ResetDebugLevels(); + + Scenes = config.Scenes; + + SceneSelectDirectFeebacks = new Dictionary(); + SceneSelectFeedback = new IntFeedback(() => (int)_activeScene); + + InitializeSceneSelectDirectFeedback(Scenes); + + _comms = comms; + _commsMonitor = new GenericCommunicationMonitor(this, _comms, config.PollTimeMs, config.WarningTimeoutMs, config.ErrorTimeoutMs, Poll); + _commsMonitor.StatusChange += OnCommunicationMonitorStatusChange; + _commsRxQueue = new GenericQueue(key + "-queue"); + + //DeviceManager.AllDevicesActivated += (sender, args) => Debug.Console(VerboseLevel, this, "All devices activated"); + + OnlineFeedback = _commsMonitor.IsOnlineFeedback; + CommunicationMonitorFeedback = new IntFeedback(() => (int)_commsMonitor.Status); + + var commsGather = new CommunicationGather(_comms, CommsDelimiter); + commsGather.LineReceived += Handle_LineRecieved; + + var socket = _comms as ISocketStatus; + if (socket != null) + { + socket.ConnectionChange += OnSocketConnectionChange; + SocketStatusFeedback = new IntFeedback(() => (int)socket.ClientStatus); + } + + Debug.Console(TraceLevel, this, "Constructing new {0} instance complete", name); + Debug.Console(TraceLevel, new string('*', 80)); + Debug.Console(TraceLevel, new string('*', 80)); + } + + /// + /// Initialize plugin device + /// + public override void Initialize() + { + Debug.Console(VerboseLevel, this, "Initializing {0}", Key); + _comms.Connect(); + _commsMonitor.Start(); + } + + private void OnCommunicationMonitorStatusChange(object sender, MonitorStatusChangeEventArgs args) + { + Debug.Console(DebugLevel, this, "Communication Status: ({0}) {1}, {2}", args.Status, args.Status.ToString(), args.Message); + } + + private void OnSocketConnectionChange(object sender, GenericSocketStatusChageEventArgs args) + { + Debug.Console(DebugLevel, this, "Socket Status: ({0}) {1}", args.Client.ClientStatus, args.Client.ClientStatus.ToString()); + + UpdateFeedbacks(); + + //if (!args.Client.IsConnected) return; + } + + #region Overrides of EssentialsBridgeableDevice + + /// + /// Links the plugin device to the EISC bridge + /// + /// + /// + /// + /// + public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { + var joinMap = new AcuityFrescoBridgeJoinMap(joinStart); + + // This adds the join map to the collection on the bridge + if (bridge != null) + { + bridge.AddJoinMap(Key, joinMap); + } + + var customJoins = JoinMapHelper.TryGetJoinMapAdvancedForDevice(joinMapKey); + if (customJoins != null) + { + joinMap.SetCustomJoinData(customJoins); + } + + Debug.Console(TraceLevel, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); + Debug.Console(TraceLevel, "Linking to Bridge Type {0}", GetType().Name); + + // link joins to bridge + trilist.SetString(joinMap.DeviceName.JoinNumber, Name); + + OnlineFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline.JoinNumber]); + CommunicationMonitorFeedback.LinkInputSig(trilist.UShortInput[joinMap.CommunicationMonitorStatus.JoinNumber]); + if (SocketStatusFeedback != null) + SocketStatusFeedback.LinkInputSig(trilist.UShortInput[joinMap.SocketStatus.JoinNumber]); + + trilist.SetUShortSigAction(joinMap.SceneSelect.JoinNumber, index => SelectScene(index)); + SceneSelectFeedback.LinkInputSig(trilist.UShortInput[joinMap.SceneSelect.JoinNumber]); + + var sceneIndex = 0; + foreach (var scene in Scenes) + { + var index = sceneIndex; + var sceneSelectJoin = (uint)(joinMap.SceneSelectDirect.JoinNumber + index); + var sceneVisibleJoin = (uint)(joinMap.SceneButtonVisibility.JoinNumber + index); + var name = scene.Name; + + Debug.Console(VerboseLevel, this, "LinkToApi: SceneSelectJoin-'{2}' | SceneVisibleJoin-'{3}' | SceneIndex-'{0}' > '{1}'", index, name, sceneSelectJoin, sceneVisibleJoin); + + trilist.SetString(sceneSelectJoin, string.IsNullOrEmpty(name) ? string.Empty : name); + trilist.SetBool(sceneVisibleJoin, string.IsNullOrEmpty(name) == false); + + trilist.SetSigTrueAction(sceneSelectJoin, () => SelectScene(index)); + SceneSelectDirectFeebacks[sceneIndex].LinkInputSig(trilist.BooleanInput[sceneSelectJoin]); + + sceneIndex++; + } + + UpdateFeedbacks(); + + trilist.OnlineStatusChange += (device, args) => + { + if (!args.DeviceOnLine) return; + + trilist.SetString(joinMap.DeviceName.JoinNumber, Name); + + UpdateFeedbacks(); + }; + } + + #endregion Overrides of EssentialsBridgeableDevice + + private void UpdateFeedbacks() + { + OnlineFeedback.FireUpdate(); + CommunicationMonitorFeedback.FireUpdate(); + if (SocketStatusFeedback != null) + SocketStatusFeedback.FireUpdate(); + + if (SceneSelectFeedback != null) + SceneSelectFeedback.FireUpdate(); + + if (SceneSelectDirectFeebacks == null) return; + + foreach (var item in SceneSelectDirectFeebacks) + { + Debug.Console(VerboseLevel, this, "UpdateFeedbacks SceneSelectDirectFeedbacks-'{0}' Value: {1}", item.Key, item.Value.BoolValue); + item.Value.FireUpdate(); + } + } + + // commonly used with ASCII based API's with a defined delimiter + private void Handle_LineRecieved(object sender, GenericCommMethodReceiveTextArgs args) + { + if (args == null || string.IsNullOrEmpty(args.Text)) + { + Debug.Console(DebugLevel, this, "Handle_LineReceived args is null or args.Text is null or empty"); + return; + } + + Debug.Console(DebugLevel, this, "Handle_LineReceived args.Text: {0}", args.Text); + + try + { + Debug.Console(DebugLevel, this, "Handle_LineReceived args.Text: {0}", args.Text); + _commsRxQueue.Enqueue(new ProcessStringMessage(args.Text, ProcessResponse)); + } + catch(Exception ex) + { + Debug.Console(DebugLevel, this, Debug.ErrorLogLevel.Error, "HandleLineReceived Exception Message: {0}", ex.Message); + Debug.Console(VerboseLevel, this, Debug.ErrorLogLevel.Error, "HandleLineRecieved Exception Stack Trace: {0}", ex.StackTrace); + if (ex.InnerException != null) Debug.Console(DebugLevel, this, Debug.ErrorLogLevel.Error, "HandleLineReceived Inner Exception: '{0}'", ex.InnerException); + } + } + + // example response + // 'scene {sceneId} {level} 0 {roomId} + // 'scene 1 100 0 b' + // 'scene 2 100 0 ab' + // 'scene 0 100 0 abc' + private void ProcessResponse(string response) + { + if (string.IsNullOrEmpty(response)) + { + Debug.Console(VerboseLevel, this, "ProcessResponse: response '{0}' is null or empty", response); + return; + } + + var expression = new Regex(@"scene (?.*) (?.*) 0 (?.*)", RegexOptions.None); + var matches = expression.Match(response); + if (!matches.Success) + { + Debug.Console(DebugLevel, this, "ProcessResponse: response '{0}', regex match failed", response.TrimEnd('\r')); + return; + } + + var responseSceneId = matches.Groups["sceneId"].Value.ToLower(); + var responseLevel = matches.Groups["level"].Value; + var responseRoomId = matches.Groups["roomId"].Value.ToLower(); + + Debug.Console(VerboseLevel, this, "ProcessResponse: responseSceneId-'{0}', responseLevel-'{1}' responseRoomId-'{2}'", + responseSceneId, responseLevel, responseRoomId); + + // TODO [ ] Add feedback logic + + } + + /// + /// Sends text to the device plugin comms + /// + /// + /// 'scene {Scene ID} {Level} [0 {room ID}]' + /// '{}' are required params + /// '[]' are optional params + /// + public void SendText(string text) + { + if (_comms.IsConnected == false) + { + Debug.Console(DebugLevel, this, Debug.ErrorLogLevel.Warning, "SendText: device comms not connected, unable to send text!"); + return; + } + + if (string.IsNullOrEmpty(text)) return; + + var cmd = string.IsNullOrEmpty(CommsDelimiter) + ? string.Format("{0}", text) + : string.Format("{0}{1}", text, CommsDelimiter); + + _comms.SendText(cmd); + } + + /// + /// Polls the device scene status for all + /// + /// + /// 'status scene {scene ID, 1-36 || ALL}' [0 {room ID, A-X}]' + /// '{}' are required params + /// '[]' are optional params + /// + public void Poll() + { + Poll(0, null); + } + + /// + /// Polls the device scene status for the scene ID + /// + /// + /// 'status scene {scene ID, 1-36 || ALL}' [0 {room ID, A-X}]' + /// '{}' are required params + /// '[]' are optional params + /// + public void Poll(uint index) + { + Poll(index, null); + } + + /// + /// Polls the device scene status for the scene ID and room ID + /// + /// + /// 'status scene {scene ID, 1-36 || ALL}' [0 {room ID, A-X}]' + /// '{}' are required params + /// '[]' are optional params + /// + public void Poll(uint index, string roomId) + { + if (index == 0 && string.IsNullOrEmpty(roomId)) + { + SendText("status scene ALL"); + } + else + { + SendText(string.IsNullOrEmpty(roomId) + ? string.Format("status scene {0}", index) + : string.Format("status scene {0} 0 {1}", index, roomId)); + } + } + + /// + /// Initializes scene select direct feedback + /// + /// + public void InitializeSceneSelectDirectFeedback(List scenes) + { + if (scenes == null) return; + + Debug.Console(TraceLevel, this, "InitiliazeSceneSelectDirectFeedback: {0} has {1} scenes configured", Key, scenes.Count); + + foreach (var scene in scenes) + { + var item = scene; + var index = scenes.FindIndex(s => s.Id.Equals(item.Id)); + + Debug.Console(VerboseLevel, this, "Scene-{0} Name: {1}, Id: {2}, RoomId: {3}, Level: {4}, IsActive: {5} ", + index, item.Name, item.Id, item.RoomId, item.Level, item.IsActive); + + SceneSelectDirectFeebacks.Add(index, new BoolFeedback(() => item.IsActive)); + } + } + + /// + /// Scene select + /// + /// + /// 'scene {SceneId, 1-36} {Level, 0-100%} 0 {RoomId, A-X}' + /// + /// + /// 'scene 36 100 0 X' + /// 'scene 2 100 0 AB' + /// 'scene 5 50 0 ABC' + /// 'scene 0 100 0 A' // lights off + /// + public void SelectScene(int index) + { + if (index < 0 || index > Scenes.Count) + { + Debug.Console(DebugLevel, this, "SelectScene: index-'{0}' is out of range (valid values 0-{1})", index, Scenes.Count); + return; + } + + Debug.Console(VerboseLevel, this, "SelectScene: index-'{0}'", index); + + var scene = Scenes[index]; + if (scene == null) + { + Debug.Console(DebugLevel, this, "SelectScene: invalid scene index-'{0}'", index); + return; + } + + if (scene.Id > 36) + { + Debug.Console(DebugLevel, this, "SelectScene: scene index-'{0}' sceneId-'{1}' is out of range (valid values 1-36)", index, scene.Id); + return; + } + + if (scene.Level > 100) + { + Debug.Console(DebugLevel, this, "SelectScene: scene index-'{0}' level-'{1}' is out of range (valid values 1-100)", index, scene.Level); + return; + } + + if (string.IsNullOrEmpty(scene.RoomId)) + { + Debug.Console(DebugLevel, this, "SelectScene: scene index-'{0}' roomId is null or empty", index); + return; + } + + var cmd = string.Format("scene {0} {1} 0 {2}", scene.Id, scene.Level, scene.RoomId); + Debug.Console(DebugLevel, this, "SelectScene: index-'{0}' cmd-'{1}'", index, cmd); + SendText(cmd); + } + + /// + /// Prints the list of scenes to console + /// + /// + /// devjson:1 {"deviceKey":"{deviceKey}", "methodName":"GetScenes", "params":[]} + /// + public void GetScenes() + { + Debug.Console(TraceLevel, this, new string('*', 80)); + Debug.Console(TraceLevel, this, "Scene List:"); + for (var i = 0; i <= Scenes.Count; i++) + { + Debug.Console(TraceLevel, this, "Scene '{0}': Id-'{1}', Level-'{2}', Room Id-'{3}'", i, Scenes[i].Id, Scenes[i].Level, Scenes[i].RoomId); + } + + Debug.Console(TraceLevel, this, new string('*', 80)); + } + + + #region DebugLevels + + /// + /// Trace level (0) + /// + public uint TraceLevel { get; set; } + + /// + /// Debug level (1) + /// + public uint DebugLevel { get; set; } + + /// + /// Verbose Level (2) + /// + public uint VerboseLevel { get; set; } + + /// + /// Resets debug levels for this device instancee + /// + /// + /// devjson:1 {"deviceKey":"{deviceKey}", "methodName":"ResetDebugLevels", "params":[]} + /// + public void ResetDebugLevels() + { + TraceLevel = 0; + DebugLevel = 1; + VerboseLevel = 2; + } + + /// + /// Sets the debug levels for this device instance + /// + /// + /// devjson:1 {"deviceKey":"{deviceKey}", "methodName":"SetDebugLevels", "params":[{level, 0-2}]} + /// + /// + public void SetDebugLevels(uint level) + { + TraceLevel = level; + DebugLevel = level; + VerboseLevel = level; + } + + #endregion + } +} + diff --git a/src/AcuityFrescoFactory.cs b/src/AcuityFrescoFactory.cs new file mode 100644 index 0000000..1c2ff0b --- /dev/null +++ b/src/AcuityFrescoFactory.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Config; + +namespace PepperDashPluginAcuityFresco +{ + /// + /// Plugin factory for devices that require communications using IBasicCommunications or custom communication methods + /// + public class AcuityFrescoFactory : EssentialsPluginDeviceFactory + { + /// + /// Plugin device factory constructor + /// + public AcuityFrescoFactory() + { + // Set the minimum Essentials Framework Version + MinimumEssentialsFrameworkVersion = "1.9.7"; + + // In the constructor we initialize the list with the typenames that will build an instance of this device + // only include unique typenames, when the constructur is used all the typenames will be evaluated in lower case. + TypeNames = new List() { "acuityfresco" }; + } + + /// + /// Builds and returns an instance of AcuityFrescoDevice + /// + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + try + { + Debug.Console(2, new string('*', 80)); + Debug.Console(2, new string('*', 80)); + Debug.Console(0, "[{0}] Factory Attempting to create new device from type: {1}", dc.Key, dc.Type); + + // get the plugin device properties configuration object & check for null + var propertiesConfig = dc.Properties.ToObject(); + if (propertiesConfig == null) + { + Debug.Console(0, "[{0}] Factory: failed to read properties config for {1}", dc.Key, dc.Name); + return null; + } + + // build the plugin device comms (for all other comms methods) & check for null + var comms = CommFactory.CreateCommForDevice(dc); + if (comms != null) return new AcuityFrescoDevice(dc.Key, dc.Name, propertiesConfig, comms); + Debug.Console(0, "[{0}] Factory: failed to create comm for {1}", dc.Key, dc.Name); + return null; + } + catch (Exception ex) + { + Debug.Console(0, "[{0}] Factory BuildDevice Exception: {1}", dc.Key, ex); + return null; + } + } + } +} \ No newline at end of file diff --git a/src/AcuityFrescoPropertiesConfig.cs b/src/AcuityFrescoPropertiesConfig.cs new file mode 100644 index 0000000..d0d7528 --- /dev/null +++ b/src/AcuityFrescoPropertiesConfig.cs @@ -0,0 +1,80 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Lighting; + +namespace PepperDashPluginAcuityFresco +{ + /// + /// Plugin device configuration object + /// + [ConfigSnippet("{\"devices\":[]}")] + public class AcuityFrescoPropertiesConfig + { + /// + /// JSON control object + /// + [JsonProperty("control")] + public EssentialsControlPropertiesConfig Control { get; set; } + + /// + /// Serializes the poll time value + /// + [JsonProperty("pollTimeMs")] + public long PollTimeMs { get; set; } + + /// + /// Serializes the warning timeout value + /// + [JsonProperty("warningTimeoutMs")] + public long WarningTimeoutMs { get; set; } + + /// + /// Serializes the error timeout value + /// + [JsonProperty("errorTimeoutMs")] + public long ErrorTimeoutMs { get; set; } + + /// + /// Scenes + /// + [JsonProperty("scenes")] + public List Scenes { get; set; } + } + + /// + /// + /// + public class AcuityFrescoScene + { + /// + /// Scene name + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Scene ID usigned integer + /// + [JsonProperty("id")] + public uint Id { get; set; } + + /// + /// Room ID used for scene recall + /// + [JsonProperty("roomId")] + public string RoomId { get; set; } + + /// + /// Optional - can be used to recall a scene with the 0-100% state + /// + [JsonProperty("level")] + public uint Level { get; set; } + + /// + /// Tracks if scene is active + /// + [JsonProperty("isActive")] + public bool IsActive { get; set; } + } +} \ No newline at end of file diff --git a/src/PepperDashPluginAcuityFresco.csproj b/src/PepperDashPluginAcuityFresco.csproj new file mode 100644 index 0000000..7f03d82 --- /dev/null +++ b/src/PepperDashPluginAcuityFresco.csproj @@ -0,0 +1,116 @@ + + + Release + AnyCPU + 9.0.30729 + 2.0 + {9D249E47-8F95-4437-A6BB-563510287AD1} + Library + Properties + PepperDashPluginAcuityFresco + PepperDashPluginAcuityFresco + {0B4745B0-194B-4BB6-8E21-E9057CA92300};{4D628B5B-2FBC-4AA6-8C16-197242AEB884};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + WindowsCE + E2BECB1F-8C8C-41ba-B736-9BE7D946A398 + 5.0 + SmartDeviceProject1 + v3.5 + Windows CE + + + + + .allowedReferenceRelatedFileExtensions + true + full + false + bin\Debug\ + DEBUG;TRACE; + prompt + 4 + 512 + true + true + off + bin\Debug\PepperDashPluginAcuityFresco.xml + + + .allowedReferenceRelatedFileExtensions + none + true + bin\Release\ + prompt + 4 + 512 + true + true + off + + + + False + ..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.UI.dll + + + False + ..\packages\PepperDashEssentials\lib\net35\Essentials Devices Common.dll + + + + False + ..\packages\PepperDashEssentials\lib\net35\PepperDashEssentials.dll + + + False + ..\packages\PepperDashEssentials\lib\net35\PepperDash_Core.dll + + + False + ..\packages\PepperDashEssentials\lib\net35\PepperDash_Essentials_Core.dll + + + False + ..\packages\PepperDashEssentials\lib\net35\PepperDash_Essentials_DM.dll + + + False + ..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll + False + + + False + ..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll + False + + + False + ..\..\..\..\ProgramData\Crestron\SDK\SimplSharpNewtonsoft.dll + + + False + ..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpPro.exe + False + + + False + ..\..\..\..\ProgramData\Crestron\SDK\SimplSharpReflectionInterface.dll + + + + + + + + + + + + + + + + rem S# Pro preparation will execute after these operations + + + + \ No newline at end of file diff --git a/src/PepperDashPluginAcuityFresco.nuspec b/src/PepperDashPluginAcuityFresco.nuspec new file mode 100644 index 0000000..d421be6 --- /dev/null +++ b/src/PepperDashPluginAcuityFresco.nuspec @@ -0,0 +1,26 @@ + + + + + PepperDash.Essentials.Plugin.Lighting.Acuity.Fresco + 1.0.0 + + PepperDash Essentials Acuity Fresco Lighting Plugin + PepperDash Technologies + pepperdash + false + MIT + + https://github.com/PepperDash/epi-lighting-acuity-fresco + Copyright 2022 + + PepperDash Essentials Acuity Fresco Lighting Plugin to expose functionality in SIMPL Windows programs using Bridges. + crestron 3series 4series + + + + + + + + diff --git a/src/PepperDashPluginAcuityFresco.sln b/src/PepperDashPluginAcuityFresco.sln new file mode 100644 index 0000000..bd067c9 --- /dev/null +++ b/src/PepperDashPluginAcuityFresco.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PepperDashPluginAcuityFresco", "PepperDashPluginAcuityFresco.csproj", "{9D249E47-8F95-4437-A6BB-563510287AD1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9D249E47-8F95-4437-A6BB-563510287AD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9D249E47-8F95-4437-A6BB-563510287AD1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9D249E47-8F95-4437-A6BB-563510287AD1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9D249E47-8F95-4437-A6BB-563510287AD1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/Properties/AssemblyInfo.cs b/src/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0d8b029 --- /dev/null +++ b/src/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Reflection; + +[assembly: AssemblyTitle("PepperDashPluginAcuityFresco")] +[assembly: AssemblyCompany("PepperDash")] +[assembly: AssemblyProduct("PepperDashPluginAcuityFresco")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyVersion("1.0.0.*")] +[assembly: AssemblyInformationalVersion("0.0.0-buildType-build#")] +[assembly: Crestron.SimplSharp.Reflection.AssemblyInformationalVersion("0.0.0-buildType-build#")] + diff --git a/src/Properties/ControlSystem.cfg b/src/Properties/ControlSystem.cfg new file mode 100644 index 0000000..e69de29