├── .gitignore ├── LICENSE ├── README.md ├── dataPointInterfaces ├── default │ ├── gui │ │ └── index.html │ └── index.js ├── emptyExample │ ├── gui │ │ └── index.html │ └── index.js └── invisible │ ├── gui │ └── index.html │ └── index.js ├── hardwareInterfaces ├── arduinoYun │ ├── index.js │ └── package.json ├── empty2Example │ └── index.js ├── emptyExample │ └── index.js ├── kodi │ ├── config.json │ └── index.js ├── mpdClient │ ├── config.json │ └── index.js ├── philipsHue │ ├── config.json │ ├── index.js │ └── package.json └── raspberryPi │ ├── config.json │ └── index.js ├── libraries ├── HybridObjectsHardwareInterfaces.js ├── HybridObjectsUtilities.js ├── HybridObjectsWebFrontend.js ├── objectDefaultFiles │ ├── bird.png │ ├── index.html │ ├── object.css │ └── object.js └── webInterface │ ├── LICENSE_BOOTSTRAP │ ├── LICENSE_DROPZONE │ ├── LICENSE_ZEROCLIPBOARD │ ├── css │ ├── bootstrap-theme.min.css │ └── bootstrap.min.css │ ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 │ └── js │ ├── ZeroClipboard.js │ ├── ZeroClipboard.swf │ ├── bootstrap-theme.min.css │ ├── bootstrap.min.css │ ├── build.js │ ├── dropzone.js │ └── dropzone.js__.js ├── objects └── README.md ├── package.json └── server.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | .idea 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # idea editing tools 24 | .idea 25 | 26 | # osx directory files 27 | .DS_Store 28 | 29 | # ignore personal objects in the object folder. 30 | objects/* 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directory 36 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 37 | node_modules 38 | 39 | # idea editing tools 40 | .idea 41 | 42 | # osx directory files 43 | .DS_Store 44 | 45 | # ignore personal objects in the object folder. 46 | objects/* -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License, version 2.0 2 | 3 | 1. Definitions 4 | 5 | 1.1. "Contributor" 6 | 7 | means each individual or legal entity that creates, contributes to the 8 | creation of, or owns Covered Software. 9 | 10 | 1.2. "Contributor Version" 11 | 12 | means the combination of the Contributions of others (if any) used by a 13 | Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | 17 | means Covered Software of a particular Contributor. 18 | 19 | 1.4. "Covered Software" 20 | 21 | means Source Code Form to which the initial Contributor has attached the 22 | notice in Exhibit A, the Executable Form of such Source Code Form, and 23 | Modifications of such Source Code Form, in each case including portions 24 | thereof. 25 | 26 | 1.5. "Incompatible With Secondary Licenses" 27 | means 28 | 29 | a. that the initial Contributor has attached the notice described in 30 | Exhibit B to the Covered Software; or 31 | 32 | b. that the Covered Software was made available under the terms of 33 | version 1.1 or earlier of the License, but not also under the terms of 34 | a Secondary License. 35 | 36 | 1.6. "Executable Form" 37 | 38 | means any form of the work other than Source Code Form. 39 | 40 | 1.7. "Larger Work" 41 | 42 | means a work that combines Covered Software with other material, in a 43 | separate file or files, that is not Covered Software. 44 | 45 | 1.8. "License" 46 | 47 | means this document. 48 | 49 | 1.9. "Licensable" 50 | 51 | means having the right to grant, to the maximum extent possible, whether 52 | at the time of the initial grant or subsequently, any and all of the 53 | rights conveyed by this License. 54 | 55 | 1.10. "Modifications" 56 | 57 | means any of the following: 58 | 59 | a. any file in Source Code Form that results from an addition to, 60 | deletion from, or modification of the contents of Covered Software; or 61 | 62 | b. any new file in Source Code Form that contains any Covered Software. 63 | 64 | 1.11. "Patent Claims" of a Contributor 65 | 66 | means any patent claim(s), including without limitation, method, 67 | process, and apparatus claims, in any patent Licensable by such 68 | Contributor that would be infringed, but for the grant of the License, 69 | by the making, using, selling, offering for sale, having made, import, 70 | or transfer of either its Contributions or its Contributor Version. 71 | 72 | 1.12. "Secondary License" 73 | 74 | means either the GNU General Public License, Version 2.0, the GNU Lesser 75 | General Public License, Version 2.1, the GNU Affero General Public 76 | License, Version 3.0, or any later versions of those licenses. 77 | 78 | 1.13. "Source Code Form" 79 | 80 | means the form of the work preferred for making modifications. 81 | 82 | 1.14. "You" (or "Your") 83 | 84 | means an individual or a legal entity exercising rights under this 85 | License. For legal entities, "You" includes any entity that controls, is 86 | controlled by, or is under common control with You. For purposes of this 87 | definition, "control" means (a) the power, direct or indirect, to cause 88 | the direction or management of such entity, whether by contract or 89 | otherwise, or (b) ownership of more than fifty percent (50%) of the 90 | outstanding shares or beneficial ownership of such entity. 91 | 92 | 93 | 2. License Grants and Conditions 94 | 95 | 2.1. Grants 96 | 97 | Each Contributor hereby grants You a world-wide, royalty-free, 98 | non-exclusive license: 99 | 100 | a. under intellectual property rights (other than patent or trademark) 101 | Licensable by such Contributor to use, reproduce, make available, 102 | modify, display, perform, distribute, and otherwise exploit its 103 | Contributions, either on an unmodified basis, with Modifications, or 104 | as part of a Larger Work; and 105 | 106 | b. under Patent Claims of such Contributor to make, use, sell, offer for 107 | sale, have made, import, and otherwise transfer either its 108 | Contributions or its Contributor Version. 109 | 110 | 2.2. Effective Date 111 | 112 | The licenses granted in Section 2.1 with respect to any Contribution 113 | become effective for each Contribution on the date the Contributor first 114 | distributes such Contribution. 115 | 116 | 2.3. Limitations on Grant Scope 117 | 118 | The licenses granted in this Section 2 are the only rights granted under 119 | this License. No additional rights or licenses will be implied from the 120 | distribution or licensing of Covered Software under this License. 121 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 122 | Contributor: 123 | 124 | a. for any code that a Contributor has removed from Covered Software; or 125 | 126 | b. for infringements caused by: (i) Your and any other third party's 127 | modifications of Covered Software, or (ii) the combination of its 128 | Contributions with other software (except as part of its Contributor 129 | Version); or 130 | 131 | c. under Patent Claims infringed by Covered Software in the absence of 132 | its Contributions. 133 | 134 | This License does not grant any rights in the trademarks, service marks, 135 | or logos of any Contributor (except as may be necessary to comply with 136 | the notice requirements in Section 3.4). 137 | 138 | 2.4. Subsequent Licenses 139 | 140 | No Contributor makes additional grants as a result of Your choice to 141 | distribute the Covered Software under a subsequent version of this 142 | License (see Section 10.2) or under the terms of a Secondary License (if 143 | permitted under the terms of Section 3.3). 144 | 145 | 2.5. Representation 146 | 147 | Each Contributor represents that the Contributor believes its 148 | Contributions are its original creation(s) or it has sufficient rights to 149 | grant the rights to its Contributions conveyed by this License. 150 | 151 | 2.6. Fair Use 152 | 153 | This License is not intended to limit any rights You have under 154 | applicable copyright doctrines of fair use, fair dealing, or other 155 | equivalents. 156 | 157 | 2.7. Conditions 158 | 159 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in 160 | Section 2.1. 161 | 162 | 163 | 3. Responsibilities 164 | 165 | 3.1. Distribution of Source Form 166 | 167 | All distribution of Covered Software in Source Code Form, including any 168 | Modifications that You create or to which You contribute, must be under 169 | the terms of this License. You must inform recipients that the Source 170 | Code Form of the Covered Software is governed by the terms of this 171 | License, and how they can obtain a copy of this License. You may not 172 | attempt to alter or restrict the recipients' rights in the Source Code 173 | Form. 174 | 175 | 3.2. Distribution of Executable Form 176 | 177 | If You distribute Covered Software in Executable Form then: 178 | 179 | a. such Covered Software must also be made available in Source Code Form, 180 | as described in Section 3.1, and You must inform recipients of the 181 | Executable Form how they can obtain a copy of such Source Code Form by 182 | reasonable means in a timely manner, at a charge no more than the cost 183 | of distribution to the recipient; and 184 | 185 | b. You may distribute such Executable Form under the terms of this 186 | License, or sublicense it under different terms, provided that the 187 | license for the Executable Form does not attempt to limit or alter the 188 | recipients' rights in the Source Code Form under this License. 189 | 190 | 3.3. Distribution of a Larger Work 191 | 192 | You may create and distribute a Larger Work under terms of Your choice, 193 | provided that You also comply with the requirements of this License for 194 | the Covered Software. If the Larger Work is a combination of Covered 195 | Software with a work governed by one or more Secondary Licenses, and the 196 | Covered Software is not Incompatible With Secondary Licenses, this 197 | License permits You to additionally distribute such Covered Software 198 | under the terms of such Secondary License(s), so that the recipient of 199 | the Larger Work may, at their option, further distribute the Covered 200 | Software under the terms of either this License or such Secondary 201 | License(s). 202 | 203 | 3.4. Notices 204 | 205 | You may not remove or alter the substance of any license notices 206 | (including copyright notices, patent notices, disclaimers of warranty, or 207 | limitations of liability) contained within the Source Code Form of the 208 | Covered Software, except that You may alter any license notices to the 209 | extent required to remedy known factual inaccuracies. 210 | 211 | 3.5. Application of Additional Terms 212 | 213 | You may choose to offer, and to charge a fee for, warranty, support, 214 | indemnity or liability obligations to one or more recipients of Covered 215 | Software. However, You may do so only on Your own behalf, and not on 216 | behalf of any Contributor. You must make it absolutely clear that any 217 | such warranty, support, indemnity, or liability obligation is offered by 218 | You alone, and You hereby agree to indemnify every Contributor for any 219 | liability incurred by such Contributor as a result of warranty, support, 220 | indemnity or liability terms You offer. You may include additional 221 | disclaimers of warranty and limitations of liability specific to any 222 | jurisdiction. 223 | 224 | 4. Inability to Comply Due to Statute or Regulation 225 | 226 | If it is impossible for You to comply with any of the terms of this License 227 | with respect to some or all of the Covered Software due to statute, 228 | judicial order, or regulation then You must: (a) comply with the terms of 229 | this License to the maximum extent possible; and (b) describe the 230 | limitations and the code they affect. Such description must be placed in a 231 | text file included with all distributions of the Covered Software under 232 | this License. Except to the extent prohibited by statute or regulation, 233 | such description must be sufficiently detailed for a recipient of ordinary 234 | skill to be able to understand it. 235 | 236 | 5. Termination 237 | 238 | 5.1. The rights granted under this License will terminate automatically if You 239 | fail to comply with any of its terms. However, if You become compliant, 240 | then the rights granted under this License from a particular Contributor 241 | are reinstated (a) provisionally, unless and until such Contributor 242 | explicitly and finally terminates Your grants, and (b) on an ongoing 243 | basis, if such Contributor fails to notify You of the non-compliance by 244 | some reasonable means prior to 60 days after You have come back into 245 | compliance. Moreover, Your grants from a particular Contributor are 246 | reinstated on an ongoing basis if such Contributor notifies You of the 247 | non-compliance by some reasonable means, this is the first time You have 248 | received notice of non-compliance with this License from such 249 | Contributor, and You become compliant prior to 30 days after Your receipt 250 | of the notice. 251 | 252 | 5.2. If You initiate litigation against any entity by asserting a patent 253 | infringement claim (excluding declaratory judgment actions, 254 | counter-claims, and cross-claims) alleging that a Contributor Version 255 | directly or indirectly infringes any patent, then the rights granted to 256 | You by any and all Contributors for the Covered Software under Section 257 | 2.1 of this License shall terminate. 258 | 259 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user 260 | license agreements (excluding distributors and resellers) which have been 261 | validly granted by You or Your distributors under this License prior to 262 | termination shall survive termination. 263 | 264 | 6. Disclaimer of Warranty 265 | 266 | Covered Software is provided under this License on an "as is" basis, 267 | without warranty of any kind, either expressed, implied, or statutory, 268 | including, without limitation, warranties that the Covered Software is free 269 | of defects, merchantable, fit for a particular purpose or non-infringing. 270 | The entire risk as to the quality and performance of the Covered Software 271 | is with You. Should any Covered Software prove defective in any respect, 272 | You (not any Contributor) assume the cost of any necessary servicing, 273 | repair, or correction. This disclaimer of warranty constitutes an essential 274 | part of this License. No use of any Covered Software is authorized under 275 | this License except under this disclaimer. 276 | 277 | 7. Limitation of Liability 278 | 279 | Under no circumstances and under no legal theory, whether tort (including 280 | negligence), contract, or otherwise, shall any Contributor, or anyone who 281 | distributes Covered Software as permitted above, be liable to You for any 282 | direct, indirect, special, incidental, or consequential damages of any 283 | character including, without limitation, damages for lost profits, loss of 284 | goodwill, work stoppage, computer failure or malfunction, or any and all 285 | other commercial damages or losses, even if such party shall have been 286 | informed of the possibility of such damages. This limitation of liability 287 | shall not apply to liability for death or personal injury resulting from 288 | such party's negligence to the extent applicable law prohibits such 289 | limitation. Some jurisdictions do not allow the exclusion or limitation of 290 | incidental or consequential damages, so this exclusion and limitation may 291 | not apply to You. 292 | 293 | 8. Litigation 294 | 295 | Any litigation relating to this License may be brought only in the courts 296 | of a jurisdiction where the defendant maintains its principal place of 297 | business and such litigation shall be governed by laws of that 298 | jurisdiction, without reference to its conflict-of-law provisions. Nothing 299 | in this Section shall prevent a party's ability to bring cross-claims or 300 | counter-claims. 301 | 302 | 9. Miscellaneous 303 | 304 | This License represents the complete agreement concerning the subject 305 | matter hereof. If any provision of this License is held to be 306 | unenforceable, such provision shall be reformed only to the extent 307 | necessary to make it enforceable. Any law or regulation which provides that 308 | the language of a contract shall be construed against the drafter shall not 309 | be used to construe this License against a Contributor. 310 | 311 | 312 | 10. Versions of the License 313 | 314 | 10.1. New Versions 315 | 316 | Mozilla Foundation is the license steward. Except as provided in Section 317 | 10.3, no one other than the license steward has the right to modify or 318 | publish new versions of this License. Each version will be given a 319 | distinguishing version number. 320 | 321 | 10.2. Effect of New Versions 322 | 323 | You may distribute the Covered Software under the terms of the version 324 | of the License under which You originally received the Covered Software, 325 | or under the terms of any subsequent version published by the license 326 | steward. 327 | 328 | 10.3. Modified Versions 329 | 330 | If you create software not governed by this License, and you want to 331 | create a new license for such software, you may create and use a 332 | modified version of this License if you rename the license and remove 333 | any references to the name of the license steward (except to note that 334 | such modified license differs from this License). 335 | 336 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 337 | Licenses If You choose to distribute Source Code Form that is 338 | Incompatible With Secondary Licenses under the terms of this version of 339 | the License, the notice described in Exhibit B of this License must be 340 | attached. 341 | 342 | Exhibit A - Source Code Form License Notice 343 | 344 | This Source Code Form is subject to the 345 | terms of the Mozilla Public License, v. 346 | 2.0. If a copy of the MPL was not 347 | distributed with this file, You can 348 | obtain one at 349 | http://mozilla.org/MPL/2.0/. 350 | 351 | If it is not possible or desirable to put the notice in a particular file, 352 | then You may include the notice in a location (such as a LICENSE file in a 353 | relevant directory) where a recipient would be likely to look for such a 354 | notice. 355 | 356 | You may add additional accurate notices of copyright ownership. 357 | 358 | Exhibit B - "Incompatible With Secondary Licenses" Notice 359 | 360 | This Source Code Form is "Incompatible 361 | With Secondary Licenses", as defined by 362 | the Mozilla Public License, v. 2.0. 363 | 364 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Overview 2 | ======== 3 | 4 | This page of notes outlines how to use a Mac OS X system to prepare an Arduino Yún linux image that turns 5 | the Arduino into a HybridObject. 6 | 7 | 8 | How to install on an Arduino Yún 9 | ================================ 10 | 11 | 1. Plug the SD card into the Arduino Yún and power it on 12 | 13 | 2. On your computer, connect to the Arduino's WiFi network, named similar to "Arduino Yun-XXXXXXXX." 14 | Using a web browser, navigate to *http://arduino.local* and enter password *arduino* when prompted. 15 | 16 | 3. Give the board a name and enter the WiFi settings for your network. 17 | 18 | 4. Expand the Yún's available space by moving the root filesystem to the SD card. 19 | See [How to expand the Yún disk space](https://www.arduino.cc/en/Tutorial/ExpandingYunDiskSpace). 20 | When using a 4 GB SD card, choose 1000 MB for the size of the data partition. 21 | 22 | After expansion is complete: 23 | 24 | 5. Upload any other sketch to remove the update sketch. 25 | 26 | 6. On your Mac OS X computer install [osxfuse](https://osxfuse.github.io/). This provides `sshfs` 27 | capability which we'll use later to conveniently mount a folder on the Yún to your computer. 28 | 29 | 7. Connect to the Yún via: `ssh root@objectname.local` 30 | 31 | Example for getting to the right folder: 32 | 33 | ```` 34 | root@so1:~# cd .. 35 | root@so1:/# cd mnt/sda1/ 36 | ```` 37 | 38 | 39 | 8. Update the software on the Yún and install the sftp server and node packages: 40 | 41 | ```` 42 | opkg update 43 | opkg install openssh-sftp-server node node-socket.io node-socket.io-client node-serialport 44 | ```` 45 | 46 | 9. Create a folder with the name "mountpoint" 47 | 48 | ```` 49 | mkdir ~/mountpoint 50 | ```` 51 | 52 | 10. Mount the arduino's filesystem to your local mountpoint: 53 | 54 | ```` 55 | sshfs root@objectname.local:/mnt/sda1/arduino ~/mountpoint 56 | ```` 57 | 58 | (To unmount: `umount ~/mountpoint`) 59 | 60 | 11. Work in the mounted folder and run your programms via the terminal. 61 | 62 | 12. To allow logins over the serial port on the Hybrid Object, uncomment in `/etc/inittab`: 63 | 64 | ```` 65 | #ttyATH0::askfirst:/bin/ash --login 66 | ```` 67 | 68 | 13. Setup a swap file as described below in section **SWAP**. 69 | 70 | 14. copy the arduino code to the sda1 SD card. 71 | 72 | 15. Install the dependences: 73 | 74 | ```` 75 | npm install 76 | ```` 77 | 78 | 79 | reboot 80 | 81 | 82 | Rename Host 83 | =========== 84 | 85 | ```` 86 | uci set system.@system[0].hostname=obj 87 | uci commit system 88 | ```` 89 | 90 | 91 | Clone Yún to SD card 92 | ==================== 93 | 94 | ```` 95 | umount /overlay 96 | dd if=/dev/mtd7ro of=/mnt/sda1/hybrid-squashfs-sysupgrade.bin 97 | ```` 98 | 99 | If you plan to disconnect power and remove the SD card, run these additional commands: 100 | 101 | ```` 102 | sync 103 | halt 104 | ```` 105 | 106 | 107 | Setup a TFTP server on your Mac 108 | =============================== 109 | 110 | Start the TFTP service on your Mac: 111 | 112 | ```` 113 | sudo launchctl load -F /System/Library/LaunchDaemons/tftp.plist 114 | sudo launchctl start com.apple.tftpd 115 | ```` 116 | 117 | Download the [Arduino Yún base images zip file from Arduino.cc](http://arduino.cc/download_handler.php?f=/openwrtyun/1/YunImage_v1.5.3.zip) 118 | and extract the three files (uboot, kernel, rootfs) from the archive. 119 | 120 | Move the unpacked base images files into the `/private/tftpboot/` folder. 121 | 122 | 123 | Reflashing U-Boot 124 | ----------------- 125 | 126 | ```` 127 | setenv serverip 192.168.1.1; 128 | setenv ipaddr 192.168.1.146; 129 | 130 | tftp 0x80060000 openwrt-ar71xx-generic-linino-u-boot.bin; 131 | erase 0x9f000000 +0x40000; 132 | cp.b $fileaddr 0x9f000000 $filesize; 133 | 134 | tftp 0x80060000 openwrt-ar71xx-generic-yun-16M-kernel.bin; 135 | erase 0x9fEa0000 +0x140000; 136 | cp.b $fileaddr 0x9fea0000 $filesize; 137 | 138 | tftp 0x80060000 openwrt-ar71xx-generic-yun-16M-rootfs-squashfs.bin; 139 | erase 0x9f050000 +0xE50000; 140 | cp.b $fileaddr 0x9f050000 $filesize; 141 | 142 | bootm 0x9fea0000 143 | ```` 144 | 145 | For more information refer to [Reflashing the OpenWrt-Yún image on the Yún](https://www.arduino.cc/en/Tutorial/YunUBootReflash). 146 | 147 | 148 | Make node app run on startup 149 | ----------------------------- 150 | 151 | TODO: 152 | Evaluate https://github.com/chovy/node-startup 153 | 154 | 155 | SWAP 156 | ==== 157 | 158 | A swap file is a special kind of file that can be used as *virtual memory* by a computer's operating system. 159 | This allows the computer's operating system to push infrequently used items from RAM to the hard disk 160 | so that new items can use the newly freed space in the actual RAM. 161 | 162 | #### Verifying Free Memory 163 | 164 | Connect to Yún using ssh (i.e. by running "ssh root@youryun.local” from terminal). Then run `free -m`. 165 | This shows your current memory memory usage in **m**egabytes, including free memory. For example: 166 | 167 | ```` 168 | total used free shared buffers 169 | Mem: 61116 43556 17560 0 9612 170 | -/+ buffers: 33944 27172 171 | Swap: 0 0 0 172 | ```` 173 | 174 | Note that the swap space shows **0**, indicating that there is no swap configured and available. 175 | After confirming the lack of swap, you can setup a file to use for swap space. 176 | 177 | #### Step 1: Create an empty file to act as a swap file 178 | 179 | While connected to the Yún through the ssh terminal, run the following command to create a 180 | 512 MB swap file named yunswapfile in folder "/swap" filled with zeroes: 181 | 182 | dd if=/dev/zero of=/swap/yunswapfile bs=1M count=512 183 | 184 | This should run for a bit and provide output like this: 185 | 186 | ```` 187 | 512+0 records in 188 | 512+0 records out 189 | ```` 190 | 191 | #### Step 2: Designate the file as a swap file 192 | 193 | The step above just created an empty file. To make sure it can be used as a swap file, run this from the shell: 194 | 195 | mkswap /swap/yunswapfile 196 | 197 | You should get output like this: 198 | 199 | ```` 200 | Setting up swapspace version 1, size = 524284 KiB 201 | no label, UUID=e3e63fad-e6f7-4d4e-a32a-a326bbe48e8c 202 | ```` 203 | 204 | #### Step 3: Load the swap file for verifying 205 | 206 | To verify that the swap file is good, try to load it by running this: 207 | 208 | swapon /swap/yunswapfile 209 | 210 | This will not provide any output if everything is cool. So verify by checking free memory. 211 | 212 | free -m 213 | 214 | This shows: 215 | 216 | ```` 217 | total used free shared buffers 218 | Mem: 61116 28644 32472 0 4888 219 | -/+ buffers: 23756 37360 220 | Swap: 524284 0 524284 221 | ```` 222 | 223 | Viola!!! Notice that swap space is now available for use by the RAM. We're not done yet, we must instruct 224 | the system to use this file for swap on boot, as show in step 4. 225 | 226 | #### Step 4: Load the swap file as part of boot sequence 227 | 228 | If you stop with Step 3, next time when you restart your Yún (linux part... either through power off/on or 229 | the Linux reset button near the LEDs) the swap file will not have been loaded. So to make sure that it gets 230 | loaded every time, you need to set the swap file as part of boot sequence. 231 | 232 | **Warning:** The steps are fairly simple, but if the steps are not executed fully you might leave an inconsistent 233 | boot config and the Linux part of the Yún may not load properly. Don't worry, since this is Arduino you can reset 234 | the whole thing easily and try again. So please execute the following cleanly after understanding them. 235 | 236 | These commands are meant to be run as **root** on your Yún. Lines beginning with `#` are interpreted as comments 237 | by the shell and are not interpreted, so they won't hurt anything if included via copy/paste: 238 | 239 | ```` 240 | #1. Add swap config entry to fstab 241 | uci add fstab swap 242 | 243 | #2. Set device config entry to swap. Make sure you provide your full swap file name 244 | uci set fstab.@swap[0].device=/swap/yunswapfile 245 | 246 | #3. Enable swap 247 | uci set fstab.@swap[0].enabled=1 248 | 249 | #4. Set file system type as "swap" 250 | uci set fstab.@swap[0].fstype=swap 251 | 252 | #5. set swap options to default 253 | uci set fstab.@swap[0].options=default 254 | 255 | #6. set fsck to 0 256 | uci set fstab.@swap[0].enabled_fsck=0 257 | 258 | #7. Commit the config changes. If you don't run commit, the config changes will not be saved. 259 | uci commit 260 | ```` 261 | 262 | That's it. Restart the Linux part of Yún (reset button near LEDs). After reboot, if you run 263 | `free -m` you should see the swap file loaded. You have successfully expanded the RAM on your 264 | Arduino Yún's Linux side. 265 | 266 | 267 | How to install on a Raspberry Pi 268 | ================================ 269 | 270 | 1. Use [NOOBS](https://www.raspberrypi.org/downloads/noobs/) to install the base Raspian image. 271 | 272 | 2. Update the system software. 273 | ```` 274 | sudo apt-get update 275 | sudo apt-get upgrade -y 276 | ```` 277 | 278 | 3. Remove the default nodejs instance and replace it with v0.12 or higher. 279 | ```` 280 | sudo apt-get remove nodejs 281 | curl -sLS https://apt.adafruit.com/add | sudo bash 282 | sudo apt-get install -y node 283 | ```` 284 | 285 | 4. Get the latest OpenHybrid Object code and download dependencies. 286 | ```` 287 | git clone https://github.com/openhybrid/object.git 288 | cd object 289 | npm install 290 | ```` 291 | 292 | 5. Run the OpenHybrid Object code. 293 | ```` 294 | node server.js 295 | ```` 296 | 297 | A this point, you should be able to navigate to port 8080 on your device and find the Object dashboard. 298 | 299 | 300 | -------------------------------------------------------------------------------- /dataPointInterfaces/default/gui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | IO 7 | 19 | 20 | 21 |
22 | 24 |
25 | 79 | 80 | -------------------------------------------------------------------------------- /dataPointInterfaces/default/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve 3 | * 4 | * .,,,;;,'''.. 5 | * .'','... ..',,,. 6 | * .,,,,,,',,',;;:;,. .,l, 7 | * .,',. ... ,;, :l. 8 | * ':;. .'.:do;;. .c ol;'. 9 | * ';;' ;.; ', .dkl';, .c :; .'.',::,,'''. 10 | * ',,;;;,. ; .,' .'''. .'. .d;''.''''. 11 | * .oxddl;::,,. ', .'''. .... .'. ,:;.. 12 | * .'cOX0OOkdoc. .,'. .. ..... 'lc. 13 | * .:;,,::co0XOko' ....''..'.'''''''. 14 | * .dxk0KKdc:cdOXKl............. .. ..,c.... 15 | * .',lxOOxl:'':xkl,',......'.... ,'. 16 | * .';:oo:... . 17 | * .cd, ╔═╗┌─┐┬─┐┬ ┬┌─┐┬─┐ . 18 | * .l; ╚═╗├┤ ├┬┘└┐┌┘├┤ ├┬┘ ' 19 | * 'l. ╚═╝└─┘┴└─ └┘ └─┘┴└─ '. 20 | * .o. ... 21 | * .''''','.;:''......... 22 | * .' .l 23 | * .:. l' 24 | * .:. .l. 25 | * .x: :k;,. 26 | * cxlc; cdc,,;;. 27 | * 'l :.. .c , 28 | * o. 29 | * ., 30 | * 31 | * ╦ ╦┬ ┬┌┐ ┬─┐┬┌┬┐ ╔═╗┌┐ ┬┌─┐┌─┐┌┬┐┌─┐ 32 | * ╠═╣└┬┘├┴┐├┬┘│ ││ ║ ║├┴┐ │├┤ │ │ └─┐ 33 | * ╩ ╩ ┴ └─┘┴└─┴─┴┘ ╚═╝└─┘└┘└─┘└─┘ ┴ └─┘ 34 | * 35 | * Created by Valentin on 10/22/14. 36 | * 37 | * Copyright (c) 2015 Valentin Heun 38 | * 39 | * All ascii characters above must be included in any redistribution. 40 | * 41 | * This Source Code Form is subject to the terms of the Mozilla Public 42 | * License, v. 2.0. If a copy of the MPL was not distributed with this 43 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 44 | */ 45 | 46 | /** 47 | * @desc prototype for a plugin. This prototype is called when a value should be changed. 48 | * It defines how this value should be transformed before sending it to the destination. 49 | * @param {object} objectID Origin object in which the related link is saved. 50 | * @param {string} linkPositionID the id of the link that is related to the call 51 | * @param {number} inputData the data that needs to be processed 52 | * @param {number} inputMode the data that needs to be processed 53 | * @param {function} callback the function that is called for when the process is rendered. 54 | * @note the callback has the same structure then the initial prototype, however inputData has changed to outputData 55 | **/ 56 | 57 | exports.render = function (objectID, linkPositionID, inputData, inputMode, callback) { 58 | var outputData = inputData; 59 | var outputMode = inputMode; 60 | 61 | callback(objectID, linkPositionID, outputData, outputMode); 62 | }; 63 | 64 | /* // example for delay 65 | exports.render = function (objectID, linkPositionID, inputData, inputMode, callback) { 66 | var outputData = inputData; 67 | var outputMode = inputMode; 68 | 69 | setTimeout(function() { 70 | callback(objectID, linkPositionID, outputData, outputMode); 71 | }, 1000); 72 | }; 73 | */ 74 | -------------------------------------------------------------------------------- /dataPointInterfaces/emptyExample/gui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IO 6 | 17 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /dataPointInterfaces/emptyExample/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve 3 | * 4 | * .,,,;;,'''.. 5 | * .'','... ..',,,. 6 | * .,,,,,,',,',;;:;,. .,l, 7 | * .,',. ... ,;, :l. 8 | * ':;. .'.:do;;. .c ol;'. 9 | * ';;' ;.; ', .dkl';, .c :; .'.',::,,'''. 10 | * ',,;;;,. ; .,' .'''. .'. .d;''.''''. 11 | * .oxddl;::,,. ', .'''. .... .'. ,:;.. 12 | * .'cOX0OOkdoc. .,'. .. ..... 'lc. 13 | * .:;,,::co0XOko' ....''..'.'''''''. 14 | * .dxk0KKdc:cdOXKl............. .. ..,c.... 15 | * .',lxOOxl:'':xkl,',......'.... ,'. 16 | * .';:oo:... . 17 | * .cd, ╔═╗┌─┐┬─┐┬ ┬┌─┐┬─┐ . 18 | * .l; ╚═╗├┤ ├┬┘└┐┌┘├┤ ├┬┘ ' 19 | * 'l. ╚═╝└─┘┴└─ └┘ └─┘┴└─ '. 20 | * .o. ... 21 | * .''''','.;:''......... 22 | * .' .l 23 | * .:. l' 24 | * .:. .l. 25 | * .x: :k;,. 26 | * cxlc; cdc,,;;. 27 | * 'l :.. .c , 28 | * o. 29 | * ., 30 | * 31 | * ╦ ╦┬ ┬┌┐ ┬─┐┬┌┬┐ ╔═╗┌┐ ┬┌─┐┌─┐┌┬┐┌─┐ 32 | * ╠═╣└┬┘├┴┐├┬┘│ ││ ║ ║├┴┐ │├┤ │ │ └─┐ 33 | * ╩ ╩ ┴ └─┘┴└─┴─┴┘ ╚═╝└─┘└┘└─┘└─┘ ┴ └─┘ 34 | * 35 | * Created by Valentin on 10/22/14. 36 | * 37 | * Copyright (c) 2015 Valentin Heun 38 | * 39 | * All ascii characters above must be included in any redistribution. 40 | * 41 | * This Source Code Form is subject to the terms of the Mozilla Public 42 | * License, v. 2.0. If a copy of the MPL was not distributed with this 43 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 44 | */ 45 | 46 | /** 47 | * @desc prototype for a plugin. This prototype is called when a value should be changed. 48 | * It defines how this value should be transformed before sending it to the destination. 49 | * @param {object} objectID Origin object in which the related link is saved. 50 | * @param {string} linkPositionID the id of the link that is related to the call 51 | * @param {number} inputData the data that needs to be processed 52 | * @param {number} inputMode the data that needs to be processed 53 | * @param {function} callback the function that is called for when the process is rendered. 54 | * @note the callback has the same structure then the initial prototype, however inputData has changed to outputData 55 | **/ 56 | 57 | exports.render = function (objectID, linkPositionID, inputData, inputMode, callback) { 58 | var outputData = inputData; 59 | var outputMode = inputMode; 60 | 61 | callback(objectID, linkPositionID, outputData, outputMode); 62 | }; 63 | 64 | /* // example for delay 65 | exports.render = function (objectID, linkPositionID, inputData, inputMode, callback) { 66 | var outputData = inputData; 67 | var outputMode = inputMode; 68 | setTimeout(function() { 69 | callback(objectID, linkPositionID, outputData, outputMode); 70 | }, 1000); 71 | }; 72 | */ 73 | -------------------------------------------------------------------------------- /dataPointInterfaces/invisible/gui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | IO 7 | 19 | 20 | 21 |
22 | 24 |
25 | 79 | 80 | -------------------------------------------------------------------------------- /dataPointInterfaces/invisible/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve 3 | * 4 | * .,,,;;,'''.. 5 | * .'','... ..',,,. 6 | * .,,,,,,',,',;;:;,. .,l, 7 | * .,',. ... ,;, :l. 8 | * ':;. .'.:do;;. .c ol;'. 9 | * ';;' ;.; ', .dkl';, .c :; .'.',::,,'''. 10 | * ',,;;;,. ; .,' .'''. .'. .d;''.''''. 11 | * .oxddl;::,,. ', .'''. .... .'. ,:;.. 12 | * .'cOX0OOkdoc. .,'. .. ..... 'lc. 13 | * .:;,,::co0XOko' ....''..'.'''''''. 14 | * .dxk0KKdc:cdOXKl............. .. ..,c.... 15 | * .',lxOOxl:'':xkl,',......'.... ,'. 16 | * .';:oo:... . 17 | * .cd, ╔═╗┌─┐┬─┐┬ ┬┌─┐┬─┐ . 18 | * .l; ╚═╗├┤ ├┬┘└┐┌┘├┤ ├┬┘ ' 19 | * 'l. ╚═╝└─┘┴└─ └┘ └─┘┴└─ '. 20 | * .o. ... 21 | * .''''','.;:''......... 22 | * .' .l 23 | * .:. l' 24 | * .:. .l. 25 | * .x: :k;,. 26 | * cxlc; cdc,,;;. 27 | * 'l :.. .c , 28 | * o. 29 | * ., 30 | * 31 | * ╦ ╦┬ ┬┌┐ ┬─┐┬┌┬┐ ╔═╗┌┐ ┬┌─┐┌─┐┌┬┐┌─┐ 32 | * ╠═╣└┬┘├┴┐├┬┘│ ││ ║ ║├┴┐ │├┤ │ │ └─┐ 33 | * ╩ ╩ ┴ └─┘┴└─┴─┴┘ ╚═╝└─┘└┘└─┘└─┘ ┴ └─┘ 34 | * 35 | * Created by Valentin on 10/22/14. 36 | * 37 | * Copyright (c) 2015 Valentin Heun 38 | * 39 | * All ascii characters above must be included in any redistribution. 40 | * 41 | * This Source Code Form is subject to the terms of the Mozilla Public 42 | * License, v. 2.0. If a copy of the MPL was not distributed with this 43 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 44 | */ 45 | 46 | /** 47 | * @desc prototype for a plugin. This prototype is called when a value should be changed. 48 | * It defines how this value should be transformed before sending it to the destination. 49 | * @param {object} objectID Origin object in which the related link is saved. 50 | * @param {string} linkPositionID the id of the link that is related to the call 51 | * @param {number} inputData the data that needs to be processed 52 | * @param {number} inputMode the data that needs to be processed 53 | * @param {function} callback the function that is called for when the process is rendered. 54 | * @note the callback has the same structure then the initial prototype, however inputData has changed to outputData 55 | **/ 56 | 57 | exports.render = function (objectID, linkPositionID, inputData, inputMode, callback) { 58 | var outputData = inputData; 59 | var outputMode = inputMode; 60 | 61 | callback(objectID, linkPositionID, outputData, outputMode); 62 | }; 63 | 64 | /* // example for delay 65 | exports.render = function (objectID, linkPositionID, inputData, inputMode, callback) { 66 | var outputData = inputData; 67 | var outputMode = inputMode; 68 | setTimeout(function() { 69 | callback(objectID, linkPositionID, outputData, outputMode); 70 | }, 1000); 71 | }; 72 | */ 73 | -------------------------------------------------------------------------------- /hardwareInterfaces/arduinoYun/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve 3 | * 4 | * .,,,;;,'''.. 5 | * .'','... ..',,,. 6 | * .,,,,,,',,',;;:;,. .,l, 7 | * .,',. ... ,;, :l. 8 | * ':;. .'.:do;;. .c ol;'. 9 | * ';;' ;.; ', .dkl';, .c :; .'.',::,,'''. 10 | * ',,;;;,. ; .,' .'''. .'. .d;''.''''. 11 | * .oxddl;::,,. ', .'''. .... .'. ,:;.. 12 | * .'cOX0OOkdoc. .,'. .. ..... 'lc. 13 | * .:;,,::co0XOko' ....''..'.'''''''. 14 | * .dxk0KKdc:cdOXKl............. .. ..,c.... 15 | * .',lxOOxl:'':xkl,',......'.... ,'. 16 | * .';:oo:... . 17 | * .cd, ╔═╗┌─┐┬─┐┬ ┬┌─┐┬─┐ . 18 | * .l; ╚═╗├┤ ├┬┘└┐┌┘├┤ ├┬┘ ' 19 | * 'l. ╚═╝└─┘┴└─ └┘ └─┘┴└─ '. 20 | * .o. ... 21 | * .''''','.;:''......... 22 | * .' .l 23 | * .:. l' 24 | * .:. .l. 25 | * .x: :k;,. 26 | * cxlc; cdc,,;;. 27 | * 'l :.. .c , 28 | * o. 29 | * ., 30 | * 31 | * ╦ ╦┬ ┬┌┐ ┬─┐┬┌┬┐ ╔═╗┌┐ ┬┌─┐┌─┐┌┬┐┌─┐ 32 | * ╠═╣└┬┘├┴┐├┬┘│ ││ ║ ║├┴┐ │├┤ │ │ └─┐ 33 | * ╩ ╩ ┴ └─┘┴└─┴─┴┘ ╚═╝└─┘└┘└─┘└─┘ ┴ └─┘ 34 | * 35 | * Created by Valentin on 10/22/14. 36 | * 37 | * Copyright (c) 2015 Valentin Heun 38 | * 39 | * All ascii characters above must be included in any redistribution. 40 | * 41 | * This Source Code Form is subject to the terms of the Mozilla Public 42 | * License, v. 2.0. If a copy of the MPL was not distributed with this 43 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 44 | */ 45 | exports.enabled = false; 46 | 47 | if (exports.enabled) { 48 | var fs = require('fs'); 49 | var _ = require('lodash'); 50 | var serialport = require("serialport"); 51 | var server = require(__dirname + '/../../libraries/HybridObjectsHardwareInterfaces'); 52 | 53 | 54 | const serialBaudRate = 115200; // baud rate for connection to arudino 55 | const serialSource = "/dev/ttyATH0"; // this is pointing to the arduino 56 | const GREEN_LED = "/sys/devices/platform/leds-gpio/leds/ds:green:usb/brightness"; 57 | 58 | function ArduinoIndex() { 59 | this.objName = null; 60 | this.ioName = null; 61 | this.index = null; 62 | } 63 | 64 | var ArduinoLookup = {}; 65 | var ArduinoLookupByIndex = {}; 66 | var FullLookup = {}; 67 | var serialPortOpen = false; 68 | 69 | 70 | ledBlinker(); 71 | 72 | 73 | //initialisation of the socket connection 74 | var SerialP = serialport.SerialPort; // localize object constructor 75 | var serialPort = new SerialP(serialSource, { 76 | parser: serialport.parsers.readline("\n"), 77 | baudrate: serialBaudRate 78 | }, false); 79 | 80 | serialPort.on('error', function (err) { 81 | console.error("Serial port error", err); 82 | }); 83 | 84 | function serialServer(serialPort) { 85 | if (server.getDebug()) console.log("opneserial"); 86 | serialPort.open(); 87 | serialPort.on("open", function () { 88 | 89 | if (server.getDebug()) console.log('Serial port opened'); 90 | serialPortOpen = true; 91 | var dataSwitch = 0; 92 | var pos = null; 93 | var objID = null; 94 | var obj = null; 95 | var object = null; 96 | var arrayID = null; 97 | var valueMode = ""; 98 | var value = null; 99 | var thisName = ""; 100 | var thisPlugin = "default"; 101 | var amount = 0; 102 | //var okCounter = 0; 103 | 104 | serialPort.on('data', function (data) { 105 | switch (dataSwitch) { 106 | case 0: 107 | if (data === "f") { 108 | //if (server.getClear()) { 109 | valueMode = "f"; 110 | dataSwitch = 1; 111 | //} 112 | } 113 | else if (data === "d") { 114 | //if (server.getClear()) { 115 | valueMode = "d"; 116 | dataSwitch = 1; 117 | //} 118 | } 119 | else if (data === "p") { // positive step value 120 | //if (server.getClear()) { 121 | valueMode = "p"; 122 | dataSwitch = 1; 123 | //} 124 | } 125 | else if (data === "n") {// negative step value 126 | //if (server.getClear()) { 127 | valueMode = "n"; 128 | dataSwitch = 1; 129 | //} 130 | } 131 | else if (data === "a") { 132 | dataSwitch = 20; 133 | } 134 | else if (data === "okbird") { 135 | 136 | serialPort.write(" \n"); 137 | serialPort.write("okbird\n"); 138 | if (server.getDebug()) console.log("ok as respond"); 139 | dataSwitch = 0; 140 | } 141 | else if (data === "def") { 142 | if (server.getDebug()) console.log("developer"); 143 | dataSwitch = 40; 144 | } 145 | else if (data === "c") { 146 | if (server.getDebug()) console.log("clear"); 147 | dataSwitch = 50; 148 | 149 | } 150 | break; 151 | case 1: 152 | arrayID = parseInt(data, 10); 153 | dataSwitch = 2; 154 | break; 155 | case 2: 156 | value = parseFloat(data); 157 | 158 | if (ArduinoLookupByIndex.hasOwnProperty(arrayID)) 159 | server.writeIOToServer(ArduinoLookupByIndex[arrayID].objName, ArduinoLookupByIndex[arrayID].ioName, value, valueMode); 160 | 161 | 162 | dataSwitch = 0; 163 | break; 164 | case 20: 165 | object = data.split("\t"); 166 | dataSwitch = 21; 167 | break; 168 | case 21: 169 | arrayID = parseInt(data, 10); 170 | dataSwitch = 23; 171 | break; 172 | case 23: 173 | thisPlugin = data; 174 | obj = object[1]; 175 | pos = object[0]; 176 | 177 | if (server.getDebug()) console.log("Add Arduino Yun"); 178 | 179 | ArduinoLookup[obj + pos] = new ArduinoIndex(); 180 | ArduinoLookup[obj + pos].objName = obj; 181 | ArduinoLookup[obj + pos].ioName = pos; 182 | ArduinoLookup[obj + pos].index = arrayID; 183 | 184 | ArduinoLookupByIndex[arrayID] = new ArduinoIndex(); 185 | ArduinoLookupByIndex[arrayID].objName = obj; 186 | ArduinoLookupByIndex[arrayID].ioName = pos; 187 | ArduinoLookupByIndex[arrayID].index = arrayID; 188 | 189 | var thisObjectID = server.getObjectIdFromObjectName(obj); 190 | 191 | if (!FullLookup.hasOwnProperty(thisObjectID)) { 192 | FullLookup[thisObjectID] = {}; 193 | } 194 | FullLookup[thisObjectID][pos] = arrayID; 195 | 196 | server.addIO(obj, pos, thisPlugin, "arduinoYun"); 197 | 198 | dataSwitch = 0; 199 | break; 200 | case 40: 201 | if (parseInt(data, 10) === 1) { 202 | server.developerOn(); 203 | } 204 | dataSwitch = 0; 205 | break; 206 | case 50: 207 | amount = parseInt(data, 10); 208 | server.clearIO("arduinoYun"); 209 | dataSwitch = 0; 210 | break; 211 | } 212 | 213 | }); 214 | 215 | // this is for when the server is started... 216 | serialPort.write(" \n"); 217 | serialPort.write("okbird\n"); 218 | 219 | }); 220 | if (server.getDebug()) console.log("no problem"); 221 | } 222 | 223 | 224 | function serialSender(serialPort, objName, ioName, value, mode, type) { 225 | 226 | if (type === "arduinoYun" && FullLookup.hasOwnProperty(objName)) { 227 | if (FullLookup[objName].hasOwnProperty(ioName)) { 228 | var index = FullLookup[objName][ioName]; 229 | var yunModes = ["f", "d", "p", "n"]; 230 | if (_.includes(yunModes, mode)) { 231 | serialPort.write(mode + "\n"); 232 | } else { 233 | serialPort.write("f\n"); 234 | } 235 | serialPort.write(index + "\n"); 236 | serialPort.write(value + "\n"); 237 | } 238 | } 239 | } 240 | 241 | 242 | exports.receive = function () { 243 | serialServer(serialPort); 244 | }; 245 | 246 | exports.send = function (objName, ioName, value, mode, type) { 247 | 248 | serialSender(serialPort, objName, ioName, value, mode, type); 249 | }; 250 | 251 | exports.init = function () { 252 | if (serialPortOpen) { 253 | serialPort.write(" \n"); 254 | serialPort.write("okbird\n"); 255 | } 256 | }; 257 | 258 | 259 | function noop_cb() { 260 | } 261 | 262 | function blinkLed() { 263 | var onTime = 300; 264 | 265 | // Turn on the LED 266 | fs.writeFile(GREEN_LED, 1, noop_cb); 267 | 268 | // Schedule turning it off 269 | setTimeout(function () { 270 | fs.writeFile(GREEN_LED, 0, noop_cb); 271 | }, onTime); 272 | } 273 | 274 | /** 275 | * Every 4 seconds, flash the LED for 300ms. 276 | * @desc blinking the LED of the Arduino in a defined interval. This indicates if the code is still running. 277 | **/ 278 | function ledBlinker() { 279 | fs.writeFile(GREEN_LED, 0, noop_cb); 280 | setInterval(blinkLed, 4000); 281 | } 282 | } -------------------------------------------------------------------------------- /hardwareInterfaces/arduinoYun/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "arduinoYun", 3 | "version": "0.0.1", 4 | "main": "index.js", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1" 7 | }, 8 | "author": "Valentin Heun (http://valentinheun.com/)", 9 | "license": "MIT" 10 | } 11 | -------------------------------------------------------------------------------- /hardwareInterfaces/empty2Example/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve 3 | * 4 | * .,,,;;,'''.. 5 | * .'','... ..',,,. 6 | * .,,,,,,',,',;;:;,. .,l, 7 | * .,',. ... ,;, :l. 8 | * ':;. .'.:do;;. .c ol;'. 9 | * ';;' ;.; ', .dkl';, .c :; .'.',::,,'''. 10 | * ',,;;;,. ; .,' .'''. .'. .d;''.''''. 11 | * .oxddl;::,,. ', .'''. .... .'. ,:;.. 12 | * .'cOX0OOkdoc. .,'. .. ..... 'lc. 13 | * .:;,,::co0XOko' ....''..'.'''''''. 14 | * .dxk0KKdc:cdOXKl............. .. ..,c.... 15 | * .',lxOOxl:'':xkl,',......'.... ,'. 16 | * .';:oo:... . 17 | * .cd, ╔═╗┌─┐┬─┐┬ ┬┌─┐┬─┐ . 18 | * .l; ╚═╗├┤ ├┬┘└┐┌┘├┤ ├┬┘ ' 19 | * 'l. ╚═╝└─┘┴└─ └┘ └─┘┴└─ '. 20 | * .o. ... 21 | * .''''','.;:''......... 22 | * .' .l 23 | * .:. l' 24 | * .:. .l. 25 | * .x: :k;,. 26 | * cxlc; cdc,,;;. 27 | * 'l :.. .c , 28 | * o. 29 | * ., 30 | * 31 | * ╦ ╦┬ ┬┌┐ ┬─┐┬┌┬┐ ╔═╗┌┐ ┬┌─┐┌─┐┌┬┐┌─┐ 32 | * ╠═╣└┬┘├┴┐├┬┘│ ││ ║ ║├┴┐ │├┤ │ │ └─┐ 33 | * ╩ ╩ ┴ └─┘┴└─┴─┴┘ ╚═╝└─┘└┘└─┘└─┘ ┴ └─┘ 34 | * 35 | * Created by Valentin on 10/22/14. 36 | * Modified by Carsten on 12/06/15. 37 | * 38 | * Copyright (c) 2015 Valentin Heun 39 | * 40 | * All ascii characters above must be included in any redistribution. 41 | * 42 | * This Source Code Form is subject to the terms of the Mozilla Public 43 | * License, v. 2.0. If a copy of the MPL was not distributed with this 44 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 45 | */ 46 | 47 | /** 48 | * Set to true to enable the hardware interface 49 | **/ 50 | exports.enabled = true; 51 | 52 | 53 | if (exports.enabled) { 54 | var server = require(__dirname + '/../../libraries/HybridObjectsHardwareInterfaces'); 55 | /** 56 | * @desc This function is called once by the server. Start the event loop of your hardware interface in here. 57 | **/ 58 | exports.receive = function () { 59 | 60 | }; 61 | 62 | /** 63 | * @desc This function is called by the server whenever data for one of your HybridObject's IO points arrives. Parse the input and write the 64 | * value to your hardware. 65 | * @param {string} objName Name of the HybridObject 66 | * @param {string} ioName Name of the IO point 67 | * @param {value} value The value 68 | * @param {string} mode Specifies the datatype of value 69 | * @param {type} type The type 70 | **/ 71 | exports.send = function (objName, ioName, value, mode, type) { 72 | 73 | }; 74 | 75 | /** 76 | * @desc prototype for an interface init. The init reinitialize the communication with the external source. 77 | * Place calls to addIO() and clearIO() in here. Call clearIO() after you have added all the IO points with addIO() calls. 78 | * @note program the init so that it can be called anytime there is a change to the amount of objects. 79 | **/ 80 | exports.init = function () { 81 | 82 | 83 | 84 | server.addIO("obj47", "hans", "default", "empty2Example"); 85 | server.addIO("obj47", "peter", "default", "empty2Example"); 86 | 87 | 88 | server.clearIO("obj47"); 89 | 90 | console.log("printthatshit"); 91 | setInterval(function(){ 92 | 93 | server.writeIOToServer("obj47", "hans", Math.random(), "f"); 94 | 95 | }, 100); 96 | 97 | }; 98 | 99 | /** 100 | * @desc This function is called once by the server when the process is being torn down. 101 | * Clean up open file handles or resources and return quickly. 102 | **/ 103 | exports.shutdown = function () { 104 | 105 | }; 106 | 107 | } -------------------------------------------------------------------------------- /hardwareInterfaces/emptyExample/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve 3 | * 4 | * .,,,;;,'''.. 5 | * .'','... ..',,,. 6 | * .,,,,,,',,',;;:;,. .,l, 7 | * .,',. ... ,;, :l. 8 | * ':;. .'.:do;;. .c ol;'. 9 | * ';;' ;.; ', .dkl';, .c :; .'.',::,,'''. 10 | * ',,;;;,. ; .,' .'''. .'. .d;''.''''. 11 | * .oxddl;::,,. ', .'''. .... .'. ,:;.. 12 | * .'cOX0OOkdoc. .,'. .. ..... 'lc. 13 | * .:;,,::co0XOko' ....''..'.'''''''. 14 | * .dxk0KKdc:cdOXKl............. .. ..,c.... 15 | * .',lxOOxl:'':xkl,',......'.... ,'. 16 | * .';:oo:... . 17 | * .cd, ╔═╗┌─┐┬─┐┬ ┬┌─┐┬─┐ . 18 | * .l; ╚═╗├┤ ├┬┘└┐┌┘├┤ ├┬┘ ' 19 | * 'l. ╚═╝└─┘┴└─ └┘ └─┘┴└─ '. 20 | * .o. ... 21 | * .''''','.;:''......... 22 | * .' .l 23 | * .:. l' 24 | * .:. .l. 25 | * .x: :k;,. 26 | * cxlc; cdc,,;;. 27 | * 'l :.. .c , 28 | * o. 29 | * ., 30 | * 31 | * ╦ ╦┬ ┬┌┐ ┬─┐┬┌┬┐ ╔═╗┌┐ ┬┌─┐┌─┐┌┬┐┌─┐ 32 | * ╠═╣└┬┘├┴┐├┬┘│ ││ ║ ║├┴┐ │├┤ │ │ └─┐ 33 | * ╩ ╩ ┴ └─┘┴└─┴─┴┘ ╚═╝└─┘└┘└─┘└─┘ ┴ └─┘ 34 | * 35 | * Created by Valentin on 10/22/14. 36 | * Modified by Carsten on 12/06/15. 37 | * 38 | * Copyright (c) 2015 Valentin Heun 39 | * 40 | * All ascii characters above must be included in any redistribution. 41 | * 42 | * This Source Code Form is subject to the terms of the Mozilla Public 43 | * License, v. 2.0. If a copy of the MPL was not distributed with this 44 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 45 | */ 46 | 47 | /** 48 | * Set to true to enable the hardware interface 49 | **/ 50 | exports.enabled = true; 51 | 52 | 53 | if (exports.enabled) { 54 | var server = require(__dirname + '/../../libraries/HybridObjectsHardwareInterfaces'); 55 | /** 56 | * @desc This function is called once by the server. Start the event loop of your hardware interface in here. 57 | **/ 58 | exports.receive = function () { 59 | 60 | }; 61 | 62 | /** 63 | * @desc This function is called by the server whenever data for one of your HybridObject's IO points arrives. Parse the input and write the 64 | * value to your hardware. 65 | * @param {string} objName Name of the HybridObject 66 | * @param {string} ioName Name of the IO point 67 | * @param {value} value The value 68 | * @param {string} mode Specifies the datatype of value 69 | * @param {type} type The type 70 | **/ 71 | exports.send = function (objName, ioName, value, mode, type) { 72 | 73 | // console.log(objName+" : "+ ioName +" : "+ value +" : "+ mode +" : "+ type); 74 | 75 | }; 76 | 77 | /** 78 | * @desc prototype for an interface init. The init reinitialize the communication with the external source. 79 | * Place calls to addIO() and clearIO() in here. Call clearIO() after you have added all the IO points with addIO() calls. 80 | * @note program the init so that it can be called anytime there is a change to the amount of objects. 81 | **/ 82 | exports.init = function () { 83 | 84 | 85 | 86 | server.addIO("obj45", "one", "default", "emptyExample"); 87 | server.addIO("obj45", "two", "default", "emptyExample"); 88 | server.addIO("obj45", "three", "default", "emptyExample"); 89 | server.addIO("obj45", "four", "default", "emptyExample"); 90 | 91 | server.addIO("obj46", "one1", "default", "emptyExample"); 92 | server.addIO("obj46", "two2", "default", "emptyExample"); 93 | 94 | server.clearIO("obj45"); 95 | server.clearIO("obj46"); 96 | 97 | 98 | console.log("printthatshit"); 99 | setInterval(function(){ 100 | 101 | server.writeIOToServer("obj45", "one", Math.random(), "f"); 102 | 103 | }, 100); 104 | 105 | }; 106 | 107 | /** 108 | * @desc This function is called once by the server when the process is being torn down. 109 | * Clean up open file handles or resources and return quickly. 110 | **/ 111 | exports.shutdown = function () { 112 | 113 | }; 114 | 115 | } -------------------------------------------------------------------------------- /hardwareInterfaces/kodi/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "MediaCentre": { 3 | "host": "192.168.178.38", 4 | "id": "MediaCentre", 5 | "port": "9090" 6 | } 7 | } -------------------------------------------------------------------------------- /hardwareInterfaces/kodi/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Carsten on 02/01/16. 3 | * 4 | * Copyright (c) 2015 Carsten Strunk 5 | * 6 | * This Source Code Form is subject to the terms of the Mozilla Public 7 | * License, v. 2.0. If a copy of the MPL was not distributed with this 8 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 | */ 10 | 11 | /* 12 | * KODI Client 13 | * 14 | * This hardware interface can communicate with a KODI Media Centre using the JSON RPC API 15 | * 16 | * http://kodi.wiki/view/JSON-RPC_API/v6 17 | * 18 | */ 19 | //Enable this hardware interface 20 | exports.enabled = false; 21 | 22 | if (exports.enabled) { 23 | var fs = require('fs'); 24 | var kodi = require('kodi-ws'); 25 | var request = require('request'); 26 | var _ = require('lodash'); 27 | var server = require(__dirname + '/../../libraries/HybridObjectsHardwareInterfaces'); 28 | 29 | var kodiServers = JSON.parse(fs.readFileSync(__dirname + "/config.json", "utf8")); 30 | 31 | 32 | /** 33 | * @desc setup() runs once, adds and clears the IO points 34 | **/ 35 | function setup() { 36 | server.developerOn(); 37 | 38 | //kodiServers = JSON.parse(fs.readFileSync(__dirname + "/config.json", "utf8")); 39 | 40 | if (server.getDebug()) console.log("KODI setup"); 41 | 42 | for (var key in kodiServers) { 43 | var kodiServer = kodiServers[key]; 44 | kodiServer.connection = null; 45 | 46 | kodi(kodiServer.host, kodiServer.port).then(function (connection) { 47 | kodiServer.connection = connection; 48 | kodiServer.connection.on('error', function (error) { console.log("KODI error: " + error) }); 49 | 50 | //Add Event Handlers 51 | kodiServer.connection.Application.OnVolumeChanged(function () { 52 | var volume = kodiServer.connection.Application.GetProperties({ properties: ['volume'] }); 53 | volume.then(function (data) { 54 | server.writeIOToServer(key, "volume", data.volume / 100, "f"); 55 | }); 56 | 57 | }); 58 | 59 | kodiServer.connection.Player.OnPause(function () { 60 | server.writeIOToServer(key, "status", 0.5, "f"); 61 | }); 62 | 63 | kodiServer.connection.Player.OnPlay(function () { 64 | server.writeIOToServer(key, "status", 1, "f"); 65 | }); 66 | 67 | kodiServer.connection.Player.OnStop(function () { 68 | server.writeIOToServer(key, "status", 0, "f"); 69 | }); 70 | 71 | }); 72 | 73 | 74 | //server.addIO(key, "volume", "default", "kodi"); 75 | //server.addIO(key, "status", "default", "kodi"); 76 | } 77 | 78 | //server.clearIO("kodi"); 79 | } 80 | 81 | 82 | exports.receive = function () { 83 | setup(); 84 | 85 | }; 86 | 87 | exports.send = function (objName, ioName, value, mode, type) { 88 | if (kodiServers.hasOwnProperty(objName) && !_.isNull(kodiServers[objName].connection)) { 89 | if (ioName == "volume") { 90 | kodiServers[objName].connection.Application.SetVolume(_.floor(value * 100)); 91 | } else if (ioName == "status") { 92 | //play, pause, stop all of the currently active players 93 | kodiServers[objName].connection.Player.GetActivePlayers().then(function (data) { 94 | for (var i = 0; i < data.length; i++) { 95 | if (value < 0.33) { 96 | kodiServers[objName].connection.Player.Stop({ playerid: data[i].playerid }); 97 | } else if (value < 0.66) { 98 | kodiServers[objName].connection.Player.PlayPause({ playerid: data[i].playerid, play:false }); 99 | } else { 100 | kodiServers[objName].connection.Player.PlayPause({ playerid: data[i].playerid, play:true }); 101 | } 102 | } 103 | 104 | }); 105 | 106 | } 107 | } 108 | }; 109 | 110 | exports.init = function () { 111 | for (var key in kodiServers) { 112 | server.addIO(key, "volume", "default", "kodi"); 113 | server.addIO(key, "status", "default", "kodi"); 114 | } 115 | 116 | server.clearIO("kodi"); 117 | }; 118 | } 119 | 120 | -------------------------------------------------------------------------------- /hardwareInterfaces/mpdClient/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Radio": { 3 | "host": "192.168.178.48", 4 | "id": "Radio", 5 | "port": "6600" 6 | } 7 | } -------------------------------------------------------------------------------- /hardwareInterfaces/mpdClient/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Carsten on 12/06/15. 3 | * 4 | * Copyright (c) 2015 Carsten Strunk 5 | * 6 | * This Source Code Form is subject to the terms of the Mozilla Public 7 | * License, v. 2.0. If a copy of the MPL was not distributed with this 8 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 | */ 10 | 11 | /* 12 | * MPD Client 13 | * 14 | * This hardware interface can communicate with a mpd server. All commands specified in the 15 | * Command Reference http://www.musicpd.org/doc/protocol/command_reference.html can be used. 16 | * 17 | * 18 | * Example mpd status output: 19 | * volume: 49 20 | * repeat: 0 21 | * random: 0 22 | * single: 0 23 | * consume: 0 24 | * playlist: 14 25 | * playlistlength: 1 26 | * mixrampdb: 0.000000 27 | * state: stop 28 | * song: 0 29 | * songid: 1 30 | * 31 | */ 32 | //Enable this hardware interface 33 | exports.enabled = false; 34 | 35 | if (exports.enabled) { 36 | var fs = require('fs'); 37 | var mpd = require('mpd'); 38 | var _ = require('lodash'); 39 | var server = require(__dirname + '/../../libraries/HybridObjectsHardwareInterfaces'); 40 | 41 | var mpdServers = JSON.parse(fs.readFileSync(__dirname + "/config.json", "utf8")); 42 | var cmd = mpd.cmd; 43 | 44 | 45 | /** 46 | * @desc setup() runs once, adds and clears the IO points 47 | **/ 48 | function setup() { 49 | server.developerOn(); 50 | 51 | for (var key in mpdServers) { 52 | var mpdServer = mpdServers[key]; 53 | mpdServer.ready = false; 54 | 55 | mpdServer.client = mpd.connect({ port: mpdServer.port, host: mpdServer.host }); 56 | 57 | mpdServer.client.on('error', function (err) { 58 | console.log("MPD " + mpdServer.id + " " + err); 59 | }); 60 | 61 | 62 | //Create listeners for mpd events 63 | mpdServer.client.on('ready', function () { 64 | mpdServer.ready = true; 65 | }); 66 | 67 | //volume has changed 68 | mpdServer.client.on('system-mixer', function () { 69 | mpdServer.client.sendCommand(cmd("status", []), function (err, msg) { 70 | if (err) console.log("Error: " + err); 71 | else { 72 | var status = mpd.parseKeyValueMessage(msg); 73 | server.writeIOToServer(key, "volume", status.volume / 100, "f"); 74 | } 75 | 76 | }); 77 | 78 | }); 79 | 80 | 81 | //playing status has changed 82 | mpdServer.client.on('system-player', function () { 83 | mpdServer.client.sendCommand(cmd("status", []), function (err, msg) { 84 | if (err) console.log("Error executing mpd command: " + err); 85 | else { 86 | var status = mpd.parseKeyValueMessage(msg); 87 | if (status.state == "stop") { 88 | server.writeIOToServer(key, "status", 0, "f"); 89 | } else if (status.state == "play") { 90 | server.writeIOToServer(key, "status", 1, "f"); 91 | } else if (status.state == "pause") { 92 | server.writeIOToServer(key, "status", 0.5, "f"); 93 | } 94 | } 95 | 96 | }); 97 | 98 | }); 99 | 100 | } 101 | } 102 | 103 | 104 | exports.receive = function () { 105 | setup(); 106 | }; 107 | 108 | exports.send = function (objName, ioName, value, mode, type) { 109 | if (server.getDebug()) console.log("Incoming: " + objName + " " + ioName + " " + value); 110 | if (mpdServers.hasOwnProperty(objName)) { 111 | if (ioName == "volume") { 112 | mpdServers[objName].client.sendCommand("setvol " + _.floor(value * 100), function (err, msg) { 113 | if (err) console.log("Error executing mpd command: " + err); 114 | }); 115 | } else if (ioName == "status") { 116 | if (value < 0.33) { 117 | if (mpdServers[objName].ready) { 118 | mpdServers[objName].client.sendCommand(cmd("stop", []), function (err, msg) { 119 | if (err) console.log("Error executing mpd command: " + err); 120 | }); 121 | } 122 | } else if (value < 0.66) { 123 | if (mpdServers[objName].ready) { 124 | mpdServers[objName].client.sendCommand(cmd("pause", []), function (err, msg) { 125 | if (err) console.log("Error executing mpd command: " + err); 126 | }); 127 | } 128 | } else { 129 | if (mpdServers[objName].ready) { 130 | mpdServers[objName].client.sendCommand(cmd("play", []), function (err, msg) { 131 | if (err) console.log("Error executing mpd command: " + err); 132 | }); 133 | } 134 | } 135 | } 136 | 137 | } 138 | 139 | }; 140 | 141 | exports.init = function () { 142 | if (server.getDebug()) console.log("mpd init()"); 143 | for (var key in mpdServers) { 144 | server.addIO(key, "volume", "default", "mpdClient"); 145 | server.addIO(key, "status", "default", "mpdClient"); 146 | } 147 | server.clearIO("mpdClient"); 148 | }; 149 | } 150 | 151 | 152 | -------------------------------------------------------------------------------- /hardwareInterfaces/philipsHue/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Light1": { 3 | "host": "localhost", 4 | "url": "/api/newdeveloper/lights/1", 5 | "id": "Light1", 6 | "port": "8000" 7 | }, 8 | "Light2": { 9 | "host": "localhost", 10 | "url": "/api/newdeveloper/lights/2", 11 | "id": "Light2", 12 | "port": "8000" 13 | } 14 | } -------------------------------------------------------------------------------- /hardwareInterfaces/philipsHue/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Carsten on 12/06/15. 3 | * Modified by Peter Som de Cerff (PCS) on 12/21/15 4 | * 5 | * Copyright (c) 2015 Carsten Strunk 6 | * 7 | * This Source Code Form is subject to the terms of the Mozilla Public 8 | * License, v. 2.0. If a copy of the MPL was not distributed with this 9 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 10 | */ 11 | 12 | /* 13 | * PHILIPS HUE CONNECTOR 14 | * 15 | * This hardware interface can communicate with philips Hue lights. The config.json file specifies the connection information 16 | * for the lamps in your setup. A light in this config file has the following attributes: 17 | * { 18 | * "host":"localhost", // ip or hostname of the philips Hue bridge 19 | * "url":"/api/newdeveloper/lights/1", // base path of the light on the bridge, replace newdeveloper with a valid username (see http://www.developers.meethue.com/documentation/getting-started) 20 | * "id":"Light1", // the name of the HybridObject 21 | * "port":"80" // port the hue bridge is listening on (80 on all bridges by default) 22 | * 23 | * } 24 | * 25 | * Some helpful resources on the Philips Hue API: 26 | * http://www.developers.meethue.com/documentation/getting-started 27 | * http://www.developers.meethue.com/documentation/lights-api 28 | * 29 | * TODO: Add some more functionality, i.e. change color or whatever the philips Hue API offers 30 | */ 31 | //Enable this hardware interface 32 | exports.enabled = false; 33 | 34 | if (exports.enabled) { 35 | 36 | 37 | var fs = require('fs'); 38 | var http = require('http'); 39 | var _ = require('lodash'); 40 | var server = require(__dirname + '/../../libraries/HybridObjectsHardwareInterfaces'); 41 | 42 | 43 | var lights = JSON.parse(fs.readFileSync(__dirname + "/config.json", "utf8")); 44 | 45 | //function Light() { 46 | // this.id; 47 | // this.host; 48 | // this.url; 49 | // this.port; 50 | //} 51 | 52 | /** 53 | * @desc setup() runs once, adds and clears the IO points 54 | **/ 55 | function setup() { 56 | server.developerOn(); 57 | //load the config file 58 | //lights = JSON.parse(fs.readFileSync(__dirname + "/config.json", "utf8")); 59 | 60 | if (server.getDebug()) console.log("setup philipsHue"); 61 | for (var key in lights) { 62 | lights[key].switch = undefined; 63 | lights[key].bri = undefined; 64 | lights[key].hue = undefined; 65 | lights[key].sat = undefined; 66 | } 67 | } 68 | 69 | 70 | /** 71 | * @desc getLightState() communicates with the philipsHue bridge and checks the state of the light 72 | * @param {Object} light the light to check 73 | * @param {function} callback function to run when the response has arrived 74 | **/ 75 | function getLightState(light, callback) { 76 | var state; 77 | 78 | var options = { 79 | host: light.host, 80 | path: light.url, 81 | port: light.port, 82 | method: 'GET', 83 | }; 84 | 85 | callbackHttp = function (response) { 86 | var str = ''; 87 | 88 | response.on('data', function (chunk) { 89 | str += chunk; 90 | }); 91 | 92 | response.on('end', function () { 93 | //TODO add some error handling 94 | state = JSON.parse(str).state; 95 | if (state.on != light.switch) { 96 | light.switch = state.on; 97 | if (state.on) { 98 | callback(light.id, "switch", 1, "d"); 99 | } else { 100 | callback(light.id, "switch", 0, "d"); 101 | } 102 | 103 | } 104 | 105 | if (state.hue != light.hue) { 106 | light.hue = state.hue; // hue is a value between 0 and 65535 107 | callback(light.id, "hue", state.hue / 65535, "f"); // map hue to [0,1] 108 | } 109 | 110 | if (state.bri != light.bri) { 111 | light.bri = state.bri; // brightness is a value between 1 and 254 112 | callback(light.id, "brightness", (state.bri - 1) / 253, "f"); 113 | } 114 | 115 | if (state.sat != light.sat) { 116 | light.sat = state.sat; 117 | callback(light.id, "saturation", state.sat / 254, "f"); 118 | } 119 | 120 | }); 121 | } 122 | 123 | 124 | 125 | var req = http.request(options, callbackHttp); 126 | req.on('error', function (e) { 127 | console.log('GetLightState HTTP error: ' + e.message); 128 | }); 129 | req.end(); 130 | 131 | } 132 | 133 | 134 | /** 135 | * @desc writeSwitchState() turns the specified light on or off 136 | * @param {float} state turns the light on if > 0.5, turns it off otherwise 137 | **/ 138 | function writeSwitchState(light, state) { 139 | var options = { 140 | host: light.host, 141 | path: light.url + "/state", 142 | port: light.port, 143 | method: 'PUT', 144 | }; 145 | 146 | 147 | var req = http.request(options, function () { }); 148 | req.on('error', function (e) { 149 | console.log('writeSwitchState HTTP error: ' + e.message); 150 | }); 151 | 152 | if (state < 0.5) { 153 | req.write('{"on":false}'); 154 | } else { 155 | req.write('{"on":true}'); 156 | } 157 | 158 | 159 | 160 | req.end(); 161 | 162 | //TODO check for success message from the bridge 163 | } 164 | 165 | 166 | /** 167 | * @desc writeBrightness() Sets the brightness of the specified light 168 | * @param {float} bri is the brightness in the range [0,1] 169 | **/ 170 | function writeBrightness(light, bri) { 171 | var options = { 172 | host: light.host, 173 | path: light.url + "/state", 174 | port: light.port, 175 | method: 'PUT', 176 | }; 177 | 178 | var req = http.request(options, function () { }); 179 | req.on('error', function (e) { 180 | console.log('writeBrightness HTTP error: ' + e.message); 181 | }); 182 | 183 | req.write('{"bri":' + _.floor(bri * 253 + 1) + '}'); 184 | 185 | req.end(); 186 | } 187 | 188 | 189 | /** 190 | * @desc writeSaturation() sets the saturation for the specified light 191 | * @param {float} sat is the saturatin in the range [0,1] 192 | **/ 193 | function writeSaturation(light, sat) { 194 | var options = { 195 | host: light.host, 196 | path: light.url + "/state", 197 | port: light.port, 198 | method: 'PUT', 199 | }; 200 | 201 | var req = http.request(options, function () { }); 202 | req.on('error', function (e) { 203 | console.log('writeSaturation HTTP error: ' + e.message); 204 | }); 205 | req.write('{"sat":' + _.floor(sat * 254) + '}'); 206 | req.end(); 207 | } 208 | 209 | 210 | /** 211 | * @desc writeHue() sets the hue for the specified light 212 | * @param {integer} hue is the hue in the range [0,1] 213 | **/ 214 | function writeHue(light, hue) { 215 | var options = { 216 | host: light.host, 217 | path: light.url + "/state", 218 | port: light.port, 219 | method: 'PUT', 220 | }; 221 | 222 | var req = http.request(options, function () { }); 223 | req.on('error', function (e) { 224 | console.log('writeHue HTTP error: ' + e.message); 225 | }); 226 | req.write('{"hue":' + _.floor(hue * 65535) + '}'); 227 | req.end(); 228 | } 229 | 230 | /** 231 | * @desc philipsHueServer() The main function, runs the setup and then periodically checks whether the lights are on. 232 | **/ 233 | function philipsHueServer() { 234 | console.log("philipsHue starting philipsHue"); 235 | setup(); 236 | 237 | 238 | if (server.getDebug()) console.log("philipsHue setup read by poll"); 239 | //TODO poll more often in productive environment 240 | for (var key in lights) { 241 | setInterval(function (light) { 242 | getLightState(light, server.writeIOToServer); 243 | }, 1000 + _.random(-250, 250), lights[key]); 244 | } 245 | 246 | } 247 | 248 | /** 249 | * @desc startGeneratorOnOff() starts a generator which periodically changes the values of the "generatorOnOff" IO point from true to false and vice versa 250 | * @param {Object} light the light to which the specifed IO point belongs 251 | **/ 252 | function startGeneratorOnOff(light) { 253 | var state = false; 254 | setInterval(function (l) { 255 | if (server.getDebug()) console.log("startGeneratorOnOff"); 256 | server.writeIOToServer(l.id, "generatorOnOff", state, "b"); 257 | if (state) { 258 | state = false; 259 | } else { 260 | state = true; 261 | } 262 | }, 5000 + _.random(-250, 250), light); 263 | } 264 | 265 | 266 | exports.receive = function () { 267 | philipsHueServer(); 268 | }; 269 | 270 | exports.send = function (objName, ioName, value, mode, type) { 271 | //Write incoming data to the specified light 272 | if (lights.hasOwnProperty(objName)) { 273 | if (ioName == "switch") { 274 | writeSwitchState(lights[objName], value); 275 | } else if (ioName == "brightness") { 276 | writeBrightness(lights[objName], value); 277 | } else if (ioName == "saturation") { 278 | writeSaturation(lights[objName], value); 279 | } else if (ioName == "hue") { 280 | writeHue(lights[objName], value); 281 | } 282 | } 283 | }; 284 | 285 | exports.init = function () { 286 | for (var key in lights) { 287 | server.addIO(key, "switch", "default", "philipsHue"); 288 | server.addIO(key, "brightness", "default", "philipsHue"); 289 | server.addIO(key, "hue", "default", "philipsHue"); 290 | server.addIO(key, "saturation", "default", "philipsHue"); 291 | } 292 | server.clearIO("philipsHue"); 293 | }; 294 | 295 | } 296 | 297 | 298 | 299 | -------------------------------------------------------------------------------- /hardwareInterfaces/philipsHue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "phillipsHue", 3 | "version": "0.0.1", 4 | "main": "index.js", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1" 7 | }, 8 | "author": "Carsten Strunk (http://teco.edu/)", 9 | "license": "MIT" 10 | } 11 | -------------------------------------------------------------------------------- /hardwareInterfaces/raspberryPi/config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "led1", 4 | "ioName": "digital", 5 | "pin": 16, 6 | "direction": "out", 7 | "edge": "none" 8 | }, 9 | { 10 | "id": "button1", 11 | "ioName": "digital", 12 | "pin": 17, 13 | "direction": "in", 14 | "edge": "both" 15 | } 16 | ] -------------------------------------------------------------------------------- /hardwareInterfaces/raspberryPi/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Created by Kevin Ortman on 12/15/14. 4 | * 5 | * Copyright (c) 2015 Kevin Ormtan 6 | * 7 | * This Source Code Form is subject to the terms of the Mozilla Public 8 | * License, v. 2.0. If a copy of the MPL was not distributed with this 9 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 10 | */ 11 | 12 | /** 13 | * Set to true to enable the hardware interface 14 | **/ 15 | exports.enabled = false; 16 | 17 | if (exports.enabled) { 18 | var fs = require('fs'), 19 | server = require(__dirname + '/../../libraries/HybridObjectsHardwareInterfaces'), 20 | GPIO = require('onoff').Gpio; 21 | 22 | /* 23 | Example item object in JSON format 24 | { 25 | "id": "button", 26 | "ioName": "digital", 27 | "pin": 17, 28 | "direction": "in", 29 | "edge": "both" 30 | } 31 | */ 32 | 33 | var items = {}; 34 | 35 | //load the config file 36 | var rawItems = JSON.parse(fs.readFileSync(__dirname + "/config.json", "utf8")); 37 | 38 | /** 39 | * @desc setup() runs once, adds and clears the IO points 40 | **/ 41 | function setup() { 42 | server.developerOn(); 43 | } 44 | 45 | /** 46 | * @desc teardown() free up any open resources 47 | **/ 48 | function teardown() { 49 | for (var key in items) { 50 | if (items.hasOwnProperty(key)) { 51 | var item = items[key]; 52 | if ("GPIO" in item) { 53 | if (server.getDebug()) console.log("raspberryPi: removing item with the id = '" + item.id + "' and ioName = '" + item.ioName + "'"); 54 | item.GPIO.unexport(); 55 | } 56 | } 57 | } 58 | items = {}; 59 | } 60 | 61 | function writeGpioToServer(err, value, item, callback) { 62 | if (err) { 63 | console.log("raspberryPi: ERROR receiving GPIO data from id = '" + item.id + "' and ioName = '" + item.ioName + "'"); 64 | console.log(err) 65 | } 66 | 67 | // only send if we don't have an error and the value has changed 68 | else if (!("lastValue" in item) || item.lastValue !== value) { 69 | item.lastValue = value; 70 | callback(item.id, item.ioName, value, "d"); // mode: d for digital 71 | } 72 | } 73 | 74 | /** 75 | * @desc This function is called once by the server. Place calls to addIO(), clearIO(), developerOn(), developerOff(), writeIOToServer() here. 76 | * Start the event loop of your hardware interface in here. Call clearIO() after you have added all the IO points with addIO() calls. 77 | **/ 78 | exports.receive = function () { 79 | if (server.getDebug()) console.log("raspberryPi: receive()"); 80 | 81 | setup(); 82 | }; 83 | 84 | /** 85 | * @desc This function is called by the server whenever data for one of your HybridObject's IO points arrives. Parse the input and write the 86 | * value to your hardware. 87 | * @param {string} objName Name of the HybridObject 88 | * @param {string} ioName Name of the IO point 89 | * @param {value} value The value 90 | * @param {string} mode Specifies the datatype of value 91 | * @param {type} type The type 92 | **/ 93 | exports.send = function (objName, ioName, value, mode, type) { 94 | var key = objName + ioName; 95 | 96 | try { 97 | if (items[key] === undefined) { 98 | if (server.getDebug()) console.log("raspberryPi: send() item not found: id = '" + objName + "' and ioName = '" + ioName + "'"); 99 | return; 100 | } 101 | items[key].GPIO.write(value); 102 | } 103 | catch (err) { 104 | if (server.getDebug()) console.log("raspberryPi: GPIO.write() error: " + err); 105 | } 106 | }; 107 | 108 | /** 109 | * @desc prototype for an interface init. The init reinitialize the communication with the external source. 110 | * @note program the init so that it can be called anytime there is a change to the amount of objects. 111 | **/ 112 | exports.init = function () { 113 | if (server.getDebug()) console.log("raspberryPi: init()"); 114 | //close all GPIO's if any are open 115 | teardown(); 116 | 117 | rawItems.forEach(function (item) { 118 | var key = item.id + item.ioName; // unique item identifier 119 | 120 | if (items[key] !== undefined) { 121 | throw ("config.json contains two or more items with the id = '" + item.id + "' and ioName = '" + item.ioName + "'"); 122 | } 123 | 124 | // if edge is not specified, fallback to the default (none) 125 | if (!("edge" in item)) { 126 | item.edge = "none" 127 | } 128 | 129 | item.GPIO = new GPIO(item.pin, item.direction, item.edge); 130 | 131 | // if this item produces input, wire it up to write results to the server 132 | if (item.direction === "in") { 133 | // watch the GPIO for state changes 134 | item.GPIO.watch(function (err, value) { 135 | writeGpioToServer(err, value, item, server.writeIOToServer); 136 | }); 137 | } 138 | 139 | if (server.getDebug()) console.log("raspberryPi: adding item with the id = '" + item.id + "' and ioName = '" + item.ioName + "'"); 140 | server.addIO(item.id, item.ioName, "default", "raspberryPi"); 141 | 142 | items[key] = item; 143 | }); 144 | 145 | server.clearIO("raspberryPi"); 146 | }; 147 | 148 | /** 149 | * @desc This function is called once by the server when the process is being torn down. 150 | * Clean up open file handles or resources and return quickly. 151 | **/ 152 | exports.shutdown = function () { 153 | if (server.getDebug()) console.log("raspberryPi: shutdown()"); 154 | 155 | teardown(); 156 | }; 157 | 158 | } -------------------------------------------------------------------------------- /libraries/HybridObjectsHardwareInterfaces.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Carsten on 12/06/2015. 3 | * Copyright (c) 2015 Carsten Strunk 4 | * 5 | * This Source Code Form is subject to the terms of the Mozilla Public 6 | * License, v. 2.0. If a copy of the MPL was not distributed with this 7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | */ 9 | 10 | /* 11 | * Hybrid Objecst Hardware Interface API 12 | * 13 | * This API is intended for users who want to create their own hardware interfaces. 14 | * To create a new hardware interface create a folder under hardwareInterfaces and create the file index.js. 15 | * You should take a look at /hardwareInterfaces/emptyExample/index.js to get started. 16 | */ 17 | 18 | 19 | 20 | var http = require('http'); 21 | var HybridObjectsUtilities = require(__dirname + '/HybridObjectsUtilities'); 22 | var _ = require('lodash'); 23 | 24 | //global variables, passed through from server.js 25 | var objectExp; 26 | var objectLookup; 27 | var globalVariables; 28 | var dirnameO; 29 | var pluginModules; 30 | var callback; 31 | var ObjectValue; 32 | 33 | //data structures to manage the IO points generated by the API user 34 | function HardwareInterface() { 35 | this.hybridObjects = {}; 36 | } 37 | 38 | function HybridObject(objName) { 39 | this.name = objName; 40 | this.ioPoints = {}; 41 | } 42 | 43 | function IOPoint(ioName) { 44 | this.name = ioName; 45 | } 46 | 47 | var hardwareInterfaces = {}; 48 | 49 | 50 | /* 51 | ********** API FUNCTIONS ********* 52 | */ 53 | 54 | 55 | /** 56 | * @desc This function writes the values passed from the hardware interface to the HybridObjects server. 57 | * @param {string} objName The name of the HybridObject 58 | * @param {string} ioName The name of the IO point 59 | * @param {} value The value to be passed on 60 | * @param {string} mode specifies the datatype of value, you can define it to be whatever you want. For example 'f' could mean value is a floating point variable. 61 | **/ 62 | exports.writeIOToServer = function (objName, ioName, value, mode) { 63 | 64 | var objKey2 = HybridObjectsUtilities.readObject(objectLookup, objName); //get globally unique object id 65 | // var valueKey = ioName + objKey2; 66 | 67 | 68 | 69 | //console.log(objectLookup); 70 | 71 | // console.log("writeIOToServer obj: "+objName + " name: "+ioName+ " value: "+value+ " mode: "+mode); 72 | 73 | if (objectExp.hasOwnProperty(objKey2)) { 74 | if (objectExp[objKey2].objectValues.hasOwnProperty(ioName)) { 75 | objectExp[objKey2].objectValues[ioName].value = value; 76 | objectExp[objKey2].objectValues[ioName].mode = mode; 77 | //callback is objectEngine in server.js. Notify data has changed. 78 | callback(objKey2, ioName, value, mode, objectExp, pluginModules); 79 | } 80 | } 81 | }; 82 | 83 | /** 84 | * @desc clearIO() removes IO points which are no longer needed. It should be called in your hardware interface after all addIO() calls have finished. 85 | * @param {string} type The name of your hardware interface (i.e. what you put in the type parameter of addIO()) 86 | **/ 87 | exports.clearIO = function (type) { 88 | if(hardwareInterfaces.hasOwnProperty(type)) { //check if IO points of the specified type have been added 89 | for (var objName in hardwareInterfaces[type].hybridObjects) { 90 | objectID = HybridObjectsUtilities.getObjectIdFromTarget(objName, dirnameO); 91 | 92 | if (!_.isUndefined(objectID) && !_.isNull(objectID) && objectID.length > 13) { 93 | for (var key in objectExp[objectID].objectValues) { 94 | if (!hardwareInterfaces[type].hybridObjects[objName].ioPoints.hasOwnProperty(objectExp[objectID].objectValues[key].name)) { 95 | if (globalVariables.debug) console.log("Deleting: " + objectID + " " + key); 96 | delete objectExp[objectID].objectValues[key]; 97 | } 98 | } 99 | 100 | } 101 | 102 | } 103 | } 104 | //TODO: clear links too 105 | if (globalVariables.debug) console.log("it's all cleared"); 106 | }; 107 | 108 | 109 | /** 110 | * @desc addIO() a new IO point to the specified HybridObject 111 | * @param {string} objName The name of the HybridObject 112 | * @param {string} ioName The name of the ioName 113 | * @param {string} plugin The name of the data conversion plugin. If you don't have your own put in "default". 114 | * @param {string} type The name of your hardware interface 115 | **/ 116 | exports.addIO = function (objName, ioName, plugin, type) { 117 | HybridObjectsUtilities.createFolder(objName, dirnameO, globalVariables.debug); 118 | 119 | var objectID = HybridObjectsUtilities.getObjectIdFromTarget(objName, dirnameO); 120 | if (globalVariables.debug) console.log("AddIO objectID: " + objectID + " " + type); 121 | 122 | //objID = ioName + objectID; 123 | 124 | if (!_.isUndefined(objectID) && !_.isNull(objectID)) { 125 | 126 | if (objectID.length > 13) { 127 | 128 | if (globalVariables.debug) console.log("I will save: " + objName + " and: " + ioName); 129 | 130 | if (objectExp.hasOwnProperty(objectID)) { 131 | objectExp[objectID].developer = globalVariables.developer; 132 | objectExp[objectID].name = objName; 133 | 134 | if (!objectExp[objectID].objectValues.hasOwnProperty(ioName)) { 135 | var thisObject = objectExp[objectID].objectValues[ioName] = new ObjectValue(); 136 | thisObject.x = HybridObjectsUtilities.randomIntInc(0, 200) - 100; 137 | thisObject.y = HybridObjectsUtilities.randomIntInc(0, 200) - 100; 138 | thisObject.frameSizeX = 47; 139 | thisObject.frameSizeY = 47; 140 | } 141 | 142 | 143 | 144 | var thisObj = objectExp[objectID].objectValues[ioName]; 145 | thisObj.name = ioName; 146 | thisObj.plugin = plugin; 147 | thisObj.type = type; 148 | 149 | //Add entries to the management data structures 150 | if(!hardwareInterfaces.hasOwnProperty(type)){ 151 | hardwareInterfaces[type] = new HardwareInterface(); 152 | } 153 | 154 | if(!hardwareInterfaces[type].hybridObjects.hasOwnProperty(objName)){ 155 | hardwareInterfaces[type].hybridObjects[objName] = new HybridObject(objName); 156 | } 157 | 158 | if(!hardwareInterfaces[type].hybridObjects[objName].ioPoints.hasOwnProperty(ioName)){ 159 | hardwareInterfaces[type].hybridObjects[objName].ioPoints[ioName] = new IOPoint(ioName); 160 | } 161 | } 162 | } 163 | } 164 | objectID = undefined; 165 | }; 166 | 167 | exports.getObjectIdFromObjectName = function (objName) { 168 | return HybridObjectsUtilities.getObjectIdFromTarget(objName, dirnameO); 169 | }; 170 | 171 | /** 172 | * @desc developerOn() Enables the developer mode for all HybridObjects and enables the developer web interface 173 | **/ 174 | exports.developerOn = function () { 175 | globalVariables.developer = true; 176 | for (var objectID in objectExp) { 177 | objectExp[objectID].developer = true; 178 | } 179 | }; 180 | 181 | 182 | 183 | /** 184 | * @desc getDebug() checks if debug mode is turned on 185 | * @return {boolean} true if debug mode is on, false otherwise 186 | **/ 187 | exports.getDebug = function () { 188 | return globalVariables.debug; 189 | }; 190 | 191 | /* 192 | ********** END API FUNCTIONS ********* 193 | */ 194 | 195 | 196 | /** 197 | * @desc setup() DO NOT call this in your hardware interface. setup() is only called from server.js to pass through some global variables. 198 | **/ 199 | exports.setup = function (objExp, objLookup, glblVars, dir, plugins, cb, objValue) { 200 | objectExp = objExp; 201 | objectLookup = objLookup; 202 | globalVariables = glblVars; 203 | dirnameO = dir; 204 | pluginModules = plugins; 205 | callback = cb; 206 | ObjectValue = objValue; 207 | }; -------------------------------------------------------------------------------- /libraries/HybridObjectsUtilities.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve 3 | * 4 | * .,,,;;,'''.. 5 | * .'','... ..',,,. 6 | * .,,,,,,',,',;;:;,. .,l, 7 | * .,',. ... ,;, :l. 8 | * ':;. .'.:do;;. .c ol;'. 9 | * ';;' ;.; ', .dkl';, .c :; .'.',::,,'''. 10 | * ',,;;;,. ; .,' .'''. .'. .d;''.''''. 11 | * .oxddl;::,,. ', .'''. .... .'. ,:;.. 12 | * .'cOX0OOkdoc. .,'. .. ..... 'lc. 13 | * .:;,,::co0XOko' ....''..'.'''''''. 14 | * .dxk0KKdc:cdOXKl............. .. ..,c.... 15 | * .',lxOOxl:'':xkl,',......'.... ,'. 16 | * .';:oo:... . 17 | * .cd, ╔═╗┌─┐┬─┐┬ ┬┌─┐┬─┐ . 18 | * .l; ╚═╗├┤ ├┬┘└┐┌┘├┤ ├┬┘ ' 19 | * 'l. ╚═╝└─┘┴└─ └┘ └─┘┴└─ '. 20 | * .o. ... 21 | * .''''','.;:''......... 22 | * .' .l 23 | * .:. l' 24 | * .:. .l. 25 | * .x: :k;,. 26 | * cxlc; cdc,,;;. 27 | * 'l :.. .c , 28 | * o. 29 | * ., 30 | * 31 | * ╦ ╦┬ ┬┌┐ ┬─┐┬┌┬┐ ╔═╗┌┐ ┬┌─┐┌─┐┌┬┐┌─┐ 32 | * ╠═╣└┬┘├┴┐├┬┘│ ││ ║ ║├┴┐ │├┤ │ │ └─┐ 33 | * ╩ ╩ ┴ └─┘┴└─┴─┴┘ ╚═╝└─┘└┘└─┘└─┘ ┴ └─┘ 34 | * 35 | * Created by Valentin on 10/22/14. 36 | * 37 | * Copyright (c) 2015 Valentin Heun 38 | * 39 | * All ascii characters above must be included in any redistribution. 40 | * 41 | * This Source Code Form is subject to the terms of the Mozilla Public 42 | * License, v. 2.0. If a copy of the MPL was not distributed with this 43 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 44 | */ 45 | 46 | 47 | 48 | /** 49 | * @desc prototype for a plugin. This prototype is called when a value should be changed. 50 | * It defines how this value should be transformed before sending it to the destination. 51 | * @param {object} objectID Origin object in which the related link is saved. 52 | * @param {string} linkPositionID the id of the link that is related to the call 53 | * @param {value} inputData the data that needs to be processed 54 | * @param {function} callback the function that is called for when the process is rendered. 55 | * @note the callback has the same structure then the initial prototype, however inputData has changed to outputData 56 | **/ 57 | 58 | var debug = false; 59 | var xml2js = require('xml2js'); 60 | var fs = require('fs'); 61 | 62 | exports.writeObject = function (objectLookup, folder, id) { 63 | objectLookup[folder] = {id: id}; 64 | }; 65 | 66 | exports.readObject = function (objectLookup, folder) { 67 | if (objectLookup.hasOwnProperty(folder)) { 68 | return objectLookup[folder].id; 69 | } else { 70 | return null; 71 | } 72 | }; 73 | 74 | exports.createFolder = function (folderVar, dirnameO, debug) { 75 | 76 | var folder = dirnameO + '/objects/' + folderVar + '/'; 77 | if (debug) console.log("Creating folder: " + folder); 78 | 79 | if (!fs.existsSync(folder)) { 80 | fs.mkdirSync(folder, "0766", function (err) { 81 | if (err) { 82 | console.log(err); 83 | res.send("ERROR! Can't make the directory! \n"); // echo the result back 84 | } 85 | }); 86 | 87 | try { 88 | // fs.createReadStream(__dirname + "/objects/object.css").pipe(fs.createWriteStream(__dirname + "/objects/" + folderVar + "/object.css")); 89 | // fs.createReadStream(dirnameO + "/libraries/objectDefaultFiles/object.js").pipe(fs.createWriteStream(dirnameO + "/objects/" + folderVar + "/object.js")); 90 | fs.createReadStream(dirnameO + "/libraries/objectDefaultFiles/index.html").pipe(fs.createWriteStream(dirnameO + "/objects/" + folderVar + "/index.html")); 91 | fs.createReadStream(dirnameO + "/libraries/objectDefaultFiles/bird.png").pipe(fs.createWriteStream(dirnameO + "/objects/" + folderVar + "/bird.png")); 92 | 93 | } catch (e) { 94 | if (debug) console.log("Could not copy source files", e); 95 | } 96 | 97 | // writeObjectToFile(tempFolderName); 98 | } 99 | }; 100 | 101 | /** 102 | * Generates a random number between the two inputs, inclusive. 103 | * @param {number} min - The minimum possible value. 104 | * @param {number} max - The maximum possible value. 105 | */ 106 | exports.randomIntInc = function (min, max) { 107 | return Math.floor(Math.random() * (max - min + 1) + min); 108 | }; 109 | 110 | /** 111 | * Generates a 12-digit unique identifier string, much of which is based on the current time. 112 | */ 113 | exports.uuidTime = function () { 114 | var dateUuidTime = new Date(); 115 | var abcUuidTime = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 116 | var stampUuidTime = parseInt(Math.floor((Math.random() * 199) + 1) + "" + dateUuidTime.getTime()).toString(36); 117 | while (stampUuidTime.length < 12) stampUuidTime = abcUuidTime.charAt(Math.floor(Math.random() * abcUuidTime.length)) + stampUuidTime; 118 | return stampUuidTime; 119 | }; 120 | 121 | exports.getObjectIdFromTarget = function (folderName, dirnameO) { 122 | 123 | var xmlFile = dirnameO + '/objects/' + folderName + '/target/target.xml'; 124 | 125 | if (fs.existsSync(xmlFile)) { 126 | var resultXML = ""; 127 | xml2js. 128 | Parser(). 129 | parseString(fs.readFileSync(xmlFile, "utf8"), 130 | function (err, result) { 131 | for (var first in result) { 132 | resultXML = result[first].Tracking[0].ImageTarget[0].$.name; 133 | break; 134 | } 135 | }); 136 | 137 | return resultXML; 138 | } else { 139 | return null; 140 | } 141 | }; 142 | 143 | /** 144 | * Saves the HybridObject as "object.json" 145 | * 146 | * @param {Object[]} objectExp - The array of objects 147 | * @param {string} object - The key used to look up the object in the objectExp array 148 | * @param {string} dirnameO - The base directory name in which an "objects" directory resides. 149 | **/ 150 | exports.writeObjectToFile = function (objectExp, object, dirnameO) { 151 | var outputFilename = dirnameO + '/objects/' + objectExp[object].folder + '/object.json'; 152 | fs.writeFile(outputFilename, JSON.stringify(objectExp[object], null, '\t'), function (err) { 153 | if (err) { 154 | console.log(err); 155 | } else { 156 | if (debug) console.log("JSON saved to " + outputFilename); 157 | } 158 | }); 159 | }; 160 | 161 | var crcTable = [0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 162 | 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 163 | 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 164 | 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 165 | 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 166 | 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 167 | 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 168 | 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 169 | 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 170 | 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 171 | 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 172 | 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 173 | 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 174 | 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 175 | 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 176 | 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 177 | 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 178 | 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 179 | 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 180 | 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 181 | 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 182 | 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 183 | 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 184 | 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 185 | 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 186 | 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 187 | 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 188 | 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 189 | 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 190 | 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 191 | 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 192 | 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 193 | 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 194 | 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 195 | 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 196 | 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 197 | 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 198 | 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 199 | 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 200 | 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 201 | 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 202 | 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 203 | 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 204 | 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 205 | 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 206 | 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 207 | 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 208 | 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 209 | 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 210 | 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 211 | 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 212 | 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 213 | 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 214 | 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 215 | 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 216 | 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 217 | 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 218 | 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 219 | 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 220 | 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 221 | 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 222 | 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 223 | 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 224 | 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D]; 225 | 226 | 227 | var crc = 0xffffffff; 228 | 229 | function crc32(data) { 230 | for(var i=0, l=data.length; i>> 8 ^ crcTable[ crc & 255 ^ data[i] ]; 233 | } 234 | return (crc ^ -1) >>> 0; 235 | } 236 | 237 | 238 | function crc16reset(){ 239 | crc = 0xffffffff; 240 | } 241 | 242 | function itob62(i) { 243 | var u = i; 244 | var b32 = ""; 245 | do 246 | { 247 | var d = Math.floor(u % 62); 248 | if (d < 10) { 249 | 250 | b32 = String.fromCharCode('0'.charCodeAt(0) + d) + b32; 251 | } 252 | else if (d < 36) { 253 | b32 = String.fromCharCode('a'.charCodeAt(0) + d - 10) + b32; 254 | } else { 255 | b32 = String.fromCharCode('A'.charCodeAt(0) + d - 36) + b32; 256 | } 257 | 258 | u = Math.floor(u / 62); 259 | 260 | } while (u > 0); 261 | 262 | return b32; 263 | } 264 | 265 | /** 266 | * @desc Generates a checksum of all files hand over with fileArray 267 | * @param objectExp hand over the overall object list 268 | * @param fileArray The array that represents all files that should be checksumed 269 | * @return 270 | **/ 271 | 272 | exports.genereateChecksums = function (objectExp,fileArray) { 273 | crc16reset(); 274 | var checksumText; 275 | for(i = 0; i< fileArray.length; i++) 276 | { 277 | if(fs.existsSync(fileArray[i])) { 278 | checksumText = itob62(crc32(fs.readFileSync(fileArray[i]))); 279 | } 280 | } 281 | console.log("created Checksum: " + checksumText); 282 | return checksumText; 283 | }; -------------------------------------------------------------------------------- /libraries/HybridObjectsWebFrontend.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve 3 | * 4 | * .,,,;;,'''.. 5 | * .'','... ..',,,. 6 | * .,,,,,,',,',;;:;,. .,l, 7 | * .,',. ... ,;, :l. 8 | * ':;. .'.:do;;. .c ol;'. 9 | * ';;' ;.; ', .dkl';, .c :; .'.',::,,'''. 10 | * ',,;;;,. ; .,' .'''. .'. .d;''.''''. 11 | * .oxddl;::,,. ', .'''. .... .'. ,:;.. 12 | * .'cOX0OOkdoc. .,'. .. ..... 'lc. 13 | * .:;,,::co0XOko' ....''..'.'''''''. 14 | * .dxk0KKdc:cdOXKl............. .. ..,c.... 15 | * .',lxOOxl:'':xkl,',......'.... ,'. 16 | * .';:oo:... . 17 | * .cd, ╔═╗┌─┐┬─┐┬ ┬┌─┐┬─┐ . 18 | * .l; ╚═╗├┤ ├┬┘└┐┌┘├┤ ├┬┘ ' 19 | * 'l. ╚═╝└─┘┴└─ └┘ └─┘┴└─ '. 20 | * .o. ... 21 | * .''''','.;:''......... 22 | * .' .l 23 | * .:. l' 24 | * .:. .l. 25 | * .x: :k;,. 26 | * cxlc; cdc,,;;. 27 | * 'l :.. .c , 28 | * o. 29 | * ., 30 | * 31 | * ╦ ╦┬ ┬┌┐ ┬─┐┬┌┬┐ ╔═╗┌┐ ┬┌─┐┌─┐┌┬┐┌─┐ 32 | * ╠═╣└┬┘├┴┐├┬┘│ ││ ║ ║├┴┐ │├┤ │ │ └─┐ 33 | * ╩ ╩ ┴ └─┘┴└─┴─┴┘ ╚═╝└─┘└┘└─┘└─┘ ┴ └─┘ 34 | * 35 | * Created by Valentin on 10/22/14. 36 | * 37 | * Copyright (c) 2015 Valentin Heun 38 | * 39 | * All ascii characters above must be included in any redistribution. 40 | * 41 | * This Source Code Form is subject to the terms of the Mozilla Public 42 | * License, v. 2.0. If a copy of the MPL was not distributed with this 43 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 44 | */ 45 | 46 | 47 | var HybridObjectsUtilities = require(__dirname+'/HybridObjectsUtilities'); 48 | var fs = require('fs'); 49 | var changeCase = require('change-case'); 50 | var debug = false; 51 | 52 | 53 | 54 | exports.printFolder = function (objectExp, dirnameO, debug, objectInterfaceFolder, objectLookup, version) { 55 | var resText = "" + 56 | "" + 57 | "" + 58 | "" + 59 | "" + 60 | ' \n' + 61 | ' \n' + 67 | // ""+ 68 | "" + 69 | '' +// background:repeating-linear-gradient(-45deg, #e4f6ff, #e4f6ff 5px, white 5px, white 10px);" >\n'+ 70 | "
" + 71 | 72 | "
" + 73 | "
" + 74 | "

Hybrid Object - Administration                Version: "+version+"

" + 75 | "
" + 76 | 77 | 78 | "
" + 79 | "
    "; 80 | 81 | 82 | var tempFiles = ""; 83 | var objectPath = dirnameO + "/objects"; 84 | var tempFiles = fs.readdirSync(objectPath).filter(function (file) { 85 | return fs.statSync(objectPath + '/' + file).isDirectory(); 86 | }); 87 | 88 | if (debug) { 89 | console.log("----------------------- objects"); 90 | for (var keykey in objectExp) { 91 | console.log(keykey); 92 | } 93 | 94 | console.log("----------------------- objects"); 95 | for (var keykey in objectExp) { 96 | console.log(keykey); 97 | } 98 | 99 | console.log("----------------------- object lookup"); 100 | 101 | for (var keykey in objectLookup) { 102 | console.log(keykey + " = " + JSON.stringify(objectLookup[keykey])); 103 | } 104 | console.log("----------------------- end" + Math.random()); 105 | } 106 | // remove hidden directories 107 | if (typeof tempFiles[0] !== "undefined") { 108 | while (tempFiles[0][0] === ".") { 109 | tempFiles.splice(0, 1); 110 | } 111 | 112 | for (var i = 0; i < tempFiles.length; i++) { 113 | resText += "
  • " + 114 | "
    " + 115 | "
    " + 116 | "" + tempFiles[i] + "" + 117 | "
    " + 118 | "
    "; 119 | 120 | if (objectExp.hasOwnProperty(HybridObjectsUtilities.readObject(objectLookup, tempFiles[i])) && fs.existsSync(objectPath + "/" + tempFiles[i] + "/target/target.xml")) { 121 | resText += 122 | " "; 123 | } else { 124 | resText += 125 | " "; 126 | } 127 | 128 | 129 | resText += " " + 138 | " " + 153 | 154 | // "
    "+ 155 | // "
    "+ 156 | 157 | // "
    " + 158 | ' ' + 162 | "
    " + 163 | "" + 164 | "" + 165 | " " + 166 | "
    " + 167 | //"
    "+ 168 | "
    " + 169 | "
  • "; 170 | 171 | 172 | } 173 | 174 | } 175 | 176 | resText += 177 | "
" + 178 | "
" + 179 | "
" + 180 | "" + 181 | "" + 182 | "
" + 183 | "
" + 184 | " " + 185 | "
" + 186 | "
" + 187 | "
" + 188 | ' ' + 189 | ' ' + 190 | 191 | 'Upload Object' + 192 | 193 | '' + 194 | ' ' + 195 | 196 | '

' + 197 | '
' + 199 | '
' + 200 | '
' + 201 | '
' + 202 | "
" + 203 | 204 | 205 | ' ' + 209 | "
" + 210 | 211 | // "upload default files"+ 212 | 213 | 214 | ' '; 265 | 266 | resText += ""; 267 | return resText; 268 | 269 | } 270 | 271 | exports.uploadInfoText = function (parm, objectLookup, objectExp, knownObjects, socketsInfo) { 272 | var objectName = HybridObjectsUtilities.readObject(objectLookup, parm); //parm + thisMacAddress; 273 | 274 | var ArduinoINstance = 0; 275 | 276 | for (subKey in objectExp) { 277 | if (subKey === objectName) { 278 | break; 279 | } 280 | ArduinoINstance++; 281 | } 282 | var text = '\n' + 283 | '\n' + 284 | ''+ 285 | ' \n' + 286 | ' \n' + 287 | '\n' + 288 | '\n' + 289 | '
\n' + 290 | '
\n' + 291 | '
\n' + 292 | '

Hybrid Object - ' + parm + ' - Info    back

\n' + 293 | '
\n' + 294 | '
\n' + 295 | '
'+ 296 | 297 | ''+ 319 | '
\n' + 320 | '\n' + 321 | '\n' + 322 | ''; 323 | 324 | 325 | return text; 326 | 327 | 328 | // var tempFolderName = tempFiles[i] + macAddress.replace(/:/gi, ''); 329 | 330 | // fill objectExp with objects named by the folders in objects 331 | // objectExp[tempFolderName] = new ObjectExp(); 332 | // objectExp[tempFolderName].folder = tempFiles[i]; 333 | } 334 | 335 | 336 | exports.uploadInfoContent = function (parm, objectLookup, objectExp, knownObjects, socketsInfo) { 337 | var objectName = HybridObjectsUtilities.readObject(objectLookup, parm); //parm + thisMacAddress; 338 | 339 | 340 | var uploadInfoTexttempArray = objectExp[objectName].objectLinks; 341 | var uploadInfoTexttempArrayValue = objectExp[objectName].objectValues; 342 | 343 | var ArduinoINstance = 0; 344 | 345 | // objectExp[objectName] 346 | 347 | for (subKey in objectExp) { 348 | if (subKey === objectName) { 349 | break; 350 | } 351 | ArduinoINstance++; 352 | } 353 | var text = 354 | '
\n' + 355 | '
\n' + 356 | ' \n' + 357 | ' \n' + 358 | ' \n' + 359 | ' \n' + 360 | ' \n' + 361 | ' \n' + 362 | ' \n' + 363 | ' \n' + 364 | ' \n'; 365 | 366 | infoCount = 0; 367 | for (subKey in uploadInfoTexttempArrayValue) { 368 | text += ""; 369 | infoCount++; 370 | } 371 | 372 | if (infoCount === 0) { 373 | text += ""; 374 | } 375 | 376 | text += 377 | ' \n' + 378 | '
IndexI/O NameValue
" + infoCount + "" + subKey + "" + uploadInfoTexttempArrayValue[subKey].value + "
- -
\n' + 379 | '
\n' + 380 | '
\n' + 381 | ' \n' + 382 | ' \n' + 383 | ' \n' + 384 | ' \n' + 385 | ' \n' + 386 | ' \n' + 387 | ' \n' + 388 | ' \n' + 389 | /* '\n'+ 390 | ' \n'+ 391 | ' \n'+ 392 | ' \n'+*/ 393 | ' \n' + 394 | ' \n' + 395 | ' \n' + 396 | ' \n' + 397 | ' \n' + 398 | ' \n' + 399 | ' \n' + 400 | ' \n' + 401 | ' \n' + 402 | ' \n' + 403 | ' \n' + 404 | ' \n' + 405 | ' \n' + 406 | ' \n' + 407 | ' \n' + 408 | ' \n' + 409 | ' \n' + 410 | ' \n' + 411 | ' \n' + 412 | ' \n' + 413 | ' \n' + 414 | '
General Info
Arduino Instance'+ArduinoINstance+'
ip' + objectExp[objectName].ip + '
version' + objectExp[objectName].version + '
sockets' + socketsInfo.sockets + '
connected' + socketsInfo.connected + '
notConnected' + socketsInfo.notConnected + '
\n' + 415 | ' \n' + 416 | ' \n' + 417 | ' \n' + 418 | ' \n' + 419 | ' \n' + 420 | ' \n' + 421 | ' \n' + 422 | ' \n'; 423 | 424 | 425 | infoCount = 0; 426 | for (subKey in knownObjects) { 427 | text += ''; 428 | infoCount++; 429 | } 430 | 431 | if (infoCount === 0) { 432 | text += ""; 433 | } 434 | 435 | text += 436 | ' \n' + 437 | '
Known Objects
' + subKey + '' + knownObjects[subKey] + '
no Object found
\n' + 438 | '
\n' + 439 | '
\n' + 440 | 441 | '
\n' + 442 | '
\n' + 443 | 444 | '
\n' + 445 | '
\n' + 446 | 447 | '
\n' + 448 | '
\n' + 449 | ' \n' + 450 | ' \n' + 451 | ' \n' + 452 | ' \n' + 453 | ' \n' + 454 | ' \n' + 455 | ' \n' + 457 | ' \n' + 458 | ' \n' + 459 | ' \n'; 460 | 461 | 462 | infoCount = 0; 463 | for (subKey in uploadInfoTexttempArray) { 464 | if(uploadInfoTexttempArray[subKey].hasOwnProperty("ObjectNameA")) 465 | text += '\n'; 466 | else 467 | text += '\n'; 468 | 469 | 470 | infoCount++; 471 | } 472 | 473 | if (infoCount === 0) { 474 | text += ""; 475 | } 476 | 477 | text += 478 | ' \n' + 479 | '
Active Link IDOrigin ObjectOrigin PossitionDestination Object\n' + 456 | ' Destination Possition
' + subKey + '' + uploadInfoTexttempArray[subKey].ObjectNameA + '' + uploadInfoTexttempArray[subKey].locationInA + '' + uploadInfoTexttempArray[subKey].ObjectNameB + '' + uploadInfoTexttempArray[subKey].locationInB + '
' + subKey + '' + uploadInfoTexttempArray[subKey].ObjectA + '' + uploadInfoTexttempArray[subKey].locationInA + '' + uploadInfoTexttempArray[subKey].ObjectB + '' + uploadInfoTexttempArray[subKey].locationInB + '
no Link found
\n' + 480 | '
\n' + 481 | '
\n' + 482 | ''; 483 | 484 | 485 | return text; 486 | 487 | 488 | // var tempFolderName = tempFiles[i] + macAddress.replace(/:/gi, ''); 489 | 490 | // fill objectExp with objects named by the folders in objects 491 | // objectExp[tempFolderName] = new ObjectExp(); 492 | // objectExp[tempFolderName].folder = tempFiles[i]; 493 | }; 494 | 495 | 496 | 497 | exports.uploadTargetText = function (parm, objectLookup, objectExp) { 498 | if(debug) console.log("target content"); 499 | var objectName = ""; 500 | if (objectExp.hasOwnProperty(HybridObjectsUtilities.readObject(objectLookup, parm))) { 501 | 502 | objectName = HybridObjectsUtilities.readObject(objectLookup, parm); 503 | } else { 504 | objectName = parm + HybridObjectsUtilities.uuidTime(); 505 | } 506 | 507 | var text = '\n' + 508 | '\n' + 509 | '\n' + 510 | ' \n' + 511 | ' \n' + 512 | ' \n' + 513 | ' \n' + 514 | ' \n' + 520 | '\n' + 521 | '\n' + 522 | '
\n' + 523 | '
\n' + 524 | '
\n' + 525 | '

Hybrid Object - ' + parm + ' - Target    back

\n' + 526 | '
\n' + 527 | '
\n' + 528 | '
\n' + 529 | '
\n' + 530 | ' 1. Upload your target source image (jpg only, < 0.5 MB)
' + 531 | ' 2. Login to the Vuforia Target Manager.
' + 532 | ' 3. Create a new or open a Device Databases.
' + 533 | ' 4. Create a target for your Object and name it exactly:
    ' + objectName + '
' + 534 | ' 5. Make sure that only this one Target is Activated.
' + 535 | ' 6. Download the database and then upload it here:
' + 536 | ' (You can just drag and drop the files anywhere in the striped area)' + 537 | '
' + 538 | '
' + 539 | ' ' + 540 | ' ' + 543 | ' ' + 544 | ' ' + 547 | '

' + 548 | '
' + 550 | '
' + 551 | '
' + 552 | '
' + 553 | ' ' + 554 | '  Upload Target zip and jpg Files ' + 555 | ' ' + 556 | '
' + 557 | '
' + 558 | ' ' + 562 | ' ' + 610 | '
' + 611 | '' + 612 | '' + 613 | '' + 614 | 615 | 616 | ''; 617 | 618 | return text; 619 | 620 | } 621 | 622 | 623 | 624 | 625 | exports.uploadTargetContent = function (parm, dirname0, objectInterfaceFolder) { 626 | if(debug) console.log("interface content"); 627 | var text = 628 | 629 | ''; 630 | 631 | var objectPath = dirname0 + "/objects/"; 632 | 633 | var objectPath2 = dirname0 + "/objects/" + parm; 634 | 635 | var tempFiles = fs.readdirSync(objectPath).filter(function (file) { 636 | return fs.statSync(objectPath + '/' + file).isDirectory(); 637 | }); 638 | 639 | 640 | var fileList; 641 | // List all files in a directory in Node.js recursively in a synchronous fashion 642 | /* var walkSync = function(dir, filelist) { 643 | var fs = fs || require('fs'), 644 | files = fs.readdirSync(dir); 645 | filelist = filelist || []; 646 | files.forEach(function(file) { 647 | if (fs.statSync(dir + '/' + file).isDirectory()) { 648 | filelist = walkSync(dir +'/'+ file + '/', filelist); 649 | folderDepth++; 650 | filelist.push("<"); 651 | filelist.push(file); 652 | } 653 | else { 654 | if(file[0] !== "." ) 655 | filelist.push(file); 656 | } 657 | } 658 | ); 659 | if(folderDepth !==0){ 660 | filelist.push(">");} 661 | 662 | return filelist; 663 | };*/ 664 | 665 | var walk = function (dir) { 666 | var results = []; 667 | var list = fs.readdirSync(dir); 668 | list.forEach(function (file) { 669 | file = dir + '/' + file; 670 | var stat = fs.statSync(file); 671 | if (stat && stat.isDirectory()) results = results.concat(walk(file)); 672 | else results.push(file) 673 | }); 674 | return results 675 | }; 676 | 677 | var listeliste = walk(objectPath2); 678 | 679 | // var folderContent = walkSync(objectPath,fileList); 680 | var folderSpace = ""; 681 | 682 | 683 | var folderOrigin = "/obj/"; 684 | 685 | var llist; 686 | 687 | folderOld = ""; 688 | 689 | text += 690 | '\n' + 691 | '\n' + 692 | '\n' + 693 | ' \n' + 694 | ' \n' + 695 | ' \n' + 696 | ' \n' + 702 | '\n' + 703 | '\n' + 704 | '
\n' + 705 | '
\n' + 706 | '
\n' + 707 | '

Hybrid Object - ' + parm + ' - File    back

\n' + 708 | '
\n' + 709 | '
\n' + 710 | '
\n' + 711 | '
\n' + 712 | ' \n' + 713 | ' \n' + 714 | ' \n' + 715 | ' \n' + 716 | ' \n' + 717 | ' \n' + 718 | ' \n' + 719 | ' \n'; 720 | 721 | 722 | for (var i = 0; i < listeliste.length; i++) { 723 | 724 | var content = listeliste[i].replace(objectPath2 + '/', '').split("/"); 725 | 726 | if (content[1] !== undefined) { 727 | if (content[0] !== folderOld) { 728 | 729 | // console.log("---" + content[0]); 730 | 731 | text += ''; 739 | 740 | } 741 | // console.log("-"+content[0]); 742 | // console.log(content[0]+" / "+content[1]); 743 | 744 | if (content[1][0] !== "." && content[1][0] !== "_") { 745 | if (debug)console.log(content[1]); 746 | var fileTypeF = changeCase.lowerCase(content[1].split(".")[1]); 747 | 748 | text += '' + content[1] + ''; 773 | } 774 | 775 | 776 | folderOld = content[0]; 777 | } else { 778 | if (content[0][0] !== "." && content[0][0] !== "_") { 779 | var fileTypeF2 = changeCase.lowerCase(content[0].split(".")[1]);//.toLowerCase(); 780 | text += '' + content[0] + ''; 807 | 808 | } else { 809 | text += 'delete'; 810 | } 811 | } 812 | 813 | } 814 | 815 | } 816 | 817 | text += 818 | 819 | '' + 820 | '' + 821 | ' \n' + 822 | '
Object Folder
  ' + content[0] + ''; 732 | 733 | var dateiTobeRemoved = parm + '/' + content[0]; 734 | text += "
" + 735 | "" + 736 | ""; 737 | 738 | text += 'delete
'; 766 | 767 | var dateiTobeRemoved = parm + '/' + content[0] + '/' + content[1]; 768 | text += "
" + 769 | "" + 770 | ""; 771 | if (debug) console.log(dateiTobeRemoved); 772 | text += 'delete
'; 798 | 799 | var dateiTobeRemoved = parm + '/' + content[0]; 800 | text += "
" + 801 | "" + 802 | ""; 803 | 804 | 805 | if (content[0] === "object.json" || content[0] === "object.css" || content[0] === "object.js") { 806 | text += 'delete
\n' + 823 | '
\n' + 824 | 'Drag and Drop your interface files anywhere on this window. Make sure that index.html is your startpoint.' + 825 | ' You can drop all your files at the same time.

' + 826 | 'object.json holds all relevant information about your object.
' + 827 | 828 | '

' + 829 | '
' + 831 | '
' + 832 | '
' + 833 | '
' + 834 | ' ' + 851 | "                " + 852 | "Add Interface Files" + 853 | "                " + 854 | ' ' + 855 | ' ' + 856 | 857 | ' ' + 861 | ' ' + 910 | '\n' + 911 | '\n'; 912 | 913 | return text; 914 | 915 | } -------------------------------------------------------------------------------- /libraries/objectDefaultFiles/bird.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openhybrid/object/f01d677c50761275d7d770f868b829b388bd438f/libraries/objectDefaultFiles/bird.png -------------------------------------------------------------------------------- /libraries/objectDefaultFiles/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Default UI 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /libraries/objectDefaultFiles/object.css: -------------------------------------------------------------------------------- 1 | body, html{ 2 | height: 100%; margin:0; padding:0; 3 | } 4 | img{ 5 | display: block; 6 | } -------------------------------------------------------------------------------- /libraries/objectDefaultFiles/object.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve 3 | * 4 | * .,,,;;,'''.. 5 | * .'','... ..',,,. 6 | * .,,,,,,',,',;;:;,. .,l, 7 | * .,',. ... ,;, :l. 8 | * ':;. .'.:do;;. .c ol;'. 9 | * ';;' ;.; ', .dkl';, .c :; .'.',::,,'''. 10 | * ',,;;;,. ; .,' .'''. .'. .d;''.''''. 11 | * .oxddl;::,,. ', .'''. .... .'. ,:;.. 12 | * .'cOX0OOkdoc. .,'. .. ..... 'lc. 13 | * .:;,,::co0XOko' ....''..'.'''''''. 14 | * .dxk0KKdc:cdOXKl............. .. ..,c.... 15 | * .',lxOOxl:'':xkl,',......'.... ,'. 16 | * .';:oo:... . 17 | * .cd, ╔═╗┌─┐┬─┐┬ ┬┌─┐┬─┐ . 18 | * .l; ╚═╗├┤ ├┬┘└┐┌┘├┤ ├┬┘ ' 19 | * 'l. ╚═╝└─┘┴└─ └┘ └─┘┴└─ '. 20 | * .o. ... 21 | * .''''','.;:''......... 22 | * .' .l 23 | * .:. l' 24 | * .:. .l. 25 | * .x: :k;,. 26 | * cxlc; cdc,,;;. 27 | * 'l :.. .c , 28 | * o. 29 | * ., 30 | * 31 | * ╦ ╦┬ ┬┌┐ ┬─┐┬┌┬┐ ╔═╗┌┐ ┬┌─┐┌─┐┌┬┐┌─┐ 32 | * ╠═╣└┬┘├┴┐├┬┘│ ││ ║ ║├┴┐ │├┤ │ │ └─┐ 33 | * ╩ ╩ ┴ └─┘┴└─┴─┴┘ ╚═╝└─┘└┘└─┘└─┘ ┴ └─┘ 34 | * 35 | * Created by Valentin on 10/22/14. 36 | * 37 | * Copyright (c) 2015 Valentin Heun 38 | * 39 | * All ascii characters above must be included in any redistribution. 40 | * 41 | * This Source Code Form is subject to the terms of the Mozilla Public 42 | * License, v. 2.0. If a copy of the MPL was not distributed with this 43 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 44 | */ 45 | 46 | // Load socket.io.js synchronous so that it is available by the time the rest of the code is executed. 47 | var xhr = new XMLHttpRequest(); 48 | xhr.open('GET', "/socket.io/socket.io.js", false); 49 | xhr.send(); 50 | 51 | //Only add script if fetch was successful 52 | if (xhr.status == 200) { 53 | var objIOScript = document.createElement('script'); 54 | objIOScript.type = "text/javascript"; 55 | objIOScript.text = xhr.responseText; 56 | document.getElementsByTagName('head')[0].appendChild(objIOScript); 57 | } else { 58 | console.log("Error XMLHttpRequest HTTP status: " + xhr.status); 59 | } 60 | var objectVersion = "1.0"; 61 | var objectExp = {}; 62 | objectExp.modelViewMatrix = []; 63 | objectExp.projectionMatrix = []; 64 | objectExp.visibility = "visible"; 65 | var objectExpSendMatrix = false; 66 | var objectExpSendFullScreen = false; 67 | var objectExpHeight ="100%"; 68 | var objectExpWidth = "100%"; 69 | 70 | // function for resizing the windows. 71 | window.addEventListener("message", function (MSG) { 72 | var msg = JSON.parse(MSG.data); 73 | 74 | if (typeof msg.pos !== "undefined") { 75 | 76 | if(objectExpSendFullScreen === false){ 77 | objectExpHeight = document.body.scrollHeight; 78 | objectExpWidth = document.body.scrollWidth; 79 | } 80 | 81 | parent.postMessage(JSON.stringify( 82 | { 83 | "pos": msg.pos, 84 | "obj": msg.obj, 85 | "height": objectExpHeight, 86 | "width":objectExpWidth, 87 | "sendMatrix" : objectExpSendMatrix, 88 | "fullScreen" : objectExpSendFullScreen 89 | } 90 | ) 91 | // this needs to contain the final interface source 92 | , "*"); 93 | 94 | objectExp.pos = msg.pos; 95 | objectExp.obj = msg.obj; 96 | } 97 | 98 | if (typeof msg.modelViewMatrix !== "undefined") { 99 | objectExp.modelViewMatrix = msg.modelViewMatrix; 100 | } 101 | 102 | if (typeof msg.projectionMatrix !== "undefined") { 103 | objectExp.projectionMatrix = msg.projectionMatrix; 104 | } 105 | 106 | if (typeof msg.visibility !== "undefined") { 107 | objectExp.visibility = msg.visibility; 108 | } 109 | 110 | }, false); 111 | 112 | // adding css styles nessasary for acurate 3D transformations. 113 | var style = document.createElement('style'); 114 | style.type = 'text/css'; 115 | style.innerHTML = 'body, html{ height: 100%; margin:0; padding:0;}'; 116 | document.getElementsByTagName('head')[0].appendChild(style); 117 | 118 | 119 | function HybridObject() { 120 | 121 | 122 | this.sendGlobalMessage = function(ohMSG) { 123 | if (typeof objectExp.pos !== "undefined") { 124 | var msgg = JSON.stringify( 125 | { 126 | "pos": objectExp.pos, 127 | "obj": objectExp.obj, 128 | "ohGlobalMessage" : ohMSG 129 | }); 130 | window.parent.postMessage(msgg 131 | , "*"); 132 | } 133 | }; 134 | 135 | this.addGlobalMessageListener = function (callback) { 136 | 137 | window.addEventListener("message", function (MSG) { 138 | var msg = JSON.parse(MSG.data); 139 | if (typeof msg.ohGlobalMessage !== "undefined") { 140 | callback(msg.ohGlobalMessage); 141 | } 142 | }, false); 143 | 144 | }; 145 | 146 | this.addMatrixListener = function (callback) { 147 | window.addEventListener("message", function (MSG) { 148 | var msg = JSON.parse(MSG.data); 149 | if (typeof msg.modelViewMatrix !== "undefined") { 150 | callback(msg.modelViewMatrix, objectExp.projectionMatrix); 151 | } 152 | }, false); 153 | 154 | }; 155 | 156 | // subscriptions 157 | this.subscribeToMatrix = function() { 158 | objectExpSendMatrix = true; 159 | if (typeof objectExp.pos !== "undefined") { 160 | 161 | if(objectExpSendFullScreen === false){ 162 | objectExpHeight = document.body.scrollHeight; 163 | objectExpWidth = document.body.scrollWidth; 164 | } 165 | 166 | parent.postMessage(JSON.stringify( 167 | { 168 | "pos": objectExp.pos, 169 | "obj": objectExp.obj, 170 | "height": objectExpHeight, 171 | "width": objectExpWidth, 172 | "sendMatrix": objectExpSendMatrix, 173 | "fullScreen": objectExpSendFullScreen 174 | }), "*"); 175 | } 176 | }; 177 | 178 | this.setFullScreenOn = function() { 179 | objectExpSendFullScreen = true; 180 | console.log("fullscreen is loaded"); 181 | if (typeof objectExp.pos !== "undefined") { 182 | 183 | objectExpHeight = "100%"; 184 | objectExpWidth = "100%"; 185 | 186 | parent.postMessage(JSON.stringify( 187 | { 188 | "pos": objectExp.pos, 189 | "obj": objectExp.obj, 190 | "height": objectExpHeight, 191 | "width": objectExpWidth, 192 | "sendMatrix": objectExpSendMatrix, 193 | "fullScreen": objectExpSendFullScreen 194 | }), "*"); 195 | } 196 | }; 197 | 198 | this.setFullScreenOff = function() { 199 | objectExpSendFullScreen = false; 200 | if (typeof objectExp.pos !== "undefined") { 201 | 202 | objectExpHeight = document.body.scrollHeight; 203 | objectExpWidth = document.body.scrollWidth; 204 | 205 | parent.postMessage(JSON.stringify( 206 | { 207 | "pos": objectExp.pos, 208 | "obj": objectExp.obj, 209 | "height": objectExpHeight, 210 | "width": objectExpWidth, 211 | "sendMatrix": objectExpSendMatrix, 212 | "fullScreen": objectExpSendFullScreen 213 | }), "*"); 214 | } 215 | }; 216 | 217 | this.getVisibility = function() { 218 | return objectExp.visibility; 219 | }; 220 | 221 | this.addVisibilityListener = function (callback) { 222 | window.addEventListener("message", function (MSG) { 223 | var msg = JSON.parse(MSG.data); 224 | if (typeof msg.visibility !== "undefined") { 225 | callback(msg.visibility); 226 | } 227 | }, false); 228 | }; 229 | 230 | this.getPossitionX = function() { 231 | if (typeof objectExp.modelViewMatrix[12] !== "undefined") { 232 | return objectExp.modelViewMatrix[12]; 233 | } else return undefined; 234 | }; 235 | 236 | this.getPossitionY = function() { 237 | if (typeof objectExp.modelViewMatrix[13] !== "undefined") { 238 | return objectExp.modelViewMatrix[13]; 239 | } else return undefined; 240 | }; 241 | 242 | this.getPossitionZ = function() { 243 | if (typeof objectExp.modelViewMatrix[14] !== "undefined") { 244 | return objectExp.modelViewMatrix[14]; 245 | } else return undefined; 246 | }; 247 | 248 | this.getProjectionMatrix = function() { 249 | if (typeof objectExp.projectionMatrix !== "undefined") { 250 | return objectExp.projectionMatrix; 251 | } else return undefined; 252 | }; 253 | 254 | this.getModelViewMatrix = function() { 255 | if (typeof objectExp.modelViewMatrix !== "undefined") { 256 | return objectExp.modelViewMatrix; 257 | } else return undefined; 258 | }; 259 | 260 | if (typeof io !== "undefined") { 261 | var thisOHObjectIdentifier = this; 262 | 263 | this.object = io.connect(); 264 | this.oldValueList = {}; 265 | 266 | this.sendServerSubscribe = setInterval(function() { 267 | if(objectExp.obj) { 268 | thisOHObjectIdentifier.object.emit('/subscribe/realityEditor', JSON.stringify({obj: objectExp.obj})); 269 | clearInterval(thisOHObjectIdentifier.sendServerSubscribe); 270 | } 271 | }, 10); 272 | 273 | this.write = function (IO, value, mode) { 274 | if(!IO in thisOHObjectIdentifier.oldValueList){ 275 | thisOHObjectIdentifier.oldValueList[IO]= null; 276 | } 277 | 278 | if (!mode) mode = 'f'; 279 | 280 | if(thisOHObjectIdentifier.oldValueList[IO] !== value) { 281 | this.object.emit('object', JSON.stringify({pos: IO, obj: objectExp.obj, value: value, mode: mode})); 282 | } 283 | thisOHObjectIdentifier.oldValueList[IO] = value; 284 | }; 285 | 286 | this.readRequest = function (IO) { 287 | this.object.emit('/object/value', JSON.stringify({pos: IO, obj: objectExp.obj})); 288 | }; 289 | 290 | this.read = function (IO, data) { 291 | if (data.pos === IO) { 292 | return data.value; 293 | } else { 294 | return undefined; 295 | } 296 | }; 297 | 298 | this.addReadListener = function (IO, callback) { 299 | thisOHObjectIdentifier.object.on("object", function (msg) { 300 | var data = JSON.parse(msg); 301 | 302 | if (typeof data.pos !== "undefined") { 303 | if (data.pos === IO) { 304 | if (typeof data.value !== "undefined") 305 | callback(data.value); 306 | } 307 | } 308 | }); 309 | }; 310 | 311 | console.log("socket.io is loaded"); 312 | } 313 | else { 314 | this.object = { 315 | on: function (x, cb) { 316 | } 317 | }; 318 | this.write = function (IO, value, mode) { 319 | }; 320 | this.read = function (IO, data) { 321 | return undefined; 322 | }; 323 | this.readRequest = function (IO) { 324 | }; 325 | console.log("socket.io is not working. This is normal when you work offline."); 326 | } 327 | } -------------------------------------------------------------------------------- /libraries/webInterface/LICENSE_BOOTSTRAP: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2015 Twitter, Inc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /libraries/webInterface/LICENSE_DROPZONE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 lev-kuznetsov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /libraries/webInterface/LICENSE_ZEROCLIPBOARD: -------------------------------------------------------------------------------- 1 | MIT License 2 | Copyright (c) 2009-2014 Jon Rohan, James M. Greene 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /libraries/webInterface/css/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.1.0 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | .btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn:active,.btn.active{background-image:none}.btn-default{background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;text-shadow:0 1px 0 #fff;border-color:#ccc}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#2b669a}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-color:#e8e8e8}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-color:#357ebd}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#222 0,#282828 100%);background-image:linear-gradient(to bottom,#222 0,#282828 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0)}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0)}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0)}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0)}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0)}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);border-color:#3278b3}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0)}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} -------------------------------------------------------------------------------- /libraries/webInterface/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openhybrid/object/f01d677c50761275d7d770f868b829b388bd438f/libraries/webInterface/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /libraries/webInterface/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openhybrid/object/f01d677c50761275d7d770f868b829b388bd438f/libraries/webInterface/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /libraries/webInterface/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openhybrid/object/f01d677c50761275d7d770f868b829b388bd438f/libraries/webInterface/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /libraries/webInterface/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openhybrid/object/f01d677c50761275d7d770f868b829b388bd438f/libraries/webInterface/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /libraries/webInterface/js/ZeroClipboard.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openhybrid/object/f01d677c50761275d7d770f868b829b388bd438f/libraries/webInterface/js/ZeroClipboard.swf -------------------------------------------------------------------------------- /libraries/webInterface/js/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.1.0 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | .btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn:active,.btn.active{background-image:none}.btn-default{background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;text-shadow:0 1px 0 #fff;border-color:#ccc}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#2b669a}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-color:#e8e8e8}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-color:#357ebd}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#222 0,#282828 100%);background-image:linear-gradient(to bottom,#222 0,#282828 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0)}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0)}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0)}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0)}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0)}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);border-color:#3278b3}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0)}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} -------------------------------------------------------------------------------- /objects/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openhybrid/object/f01d677c50761275d7d770f868b829b388bd438f/objects/README.md -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "HybridObjects", 3 | "version": "0.3.1", 4 | "description": "", 5 | "main": "server.js", 6 | "dependencies": { 7 | "archiver": "^0.14.2", 8 | "body-parser": "^1.9.2", 9 | "change-case": "^2.2.0", 10 | "cheerio": "0.19.0", 11 | "cors": "^2.5.0", 12 | "decompress-zip": "^0.1.0", 13 | "express": "^4.11.0", 14 | "formidable": "^1.0.16", 15 | "fs-extra": "^0.12.0", 16 | "fstream": "^1.0.4", 17 | "getmac": "^1.0.6", 18 | "ip": "^0.3.2", 19 | "lodash": "^3.10.1", 20 | "node-watch": "^0.3.4", 21 | "onoff": "^1.0.3", 22 | "serialport": "^3.0.1", 23 | "socket.io": "^1.2.0", 24 | "socket.io-client": "^1.2.0", 25 | "unzip": "^0.1.11", 26 | "watch": "^0.13.0", 27 | "xml2js": "^0.4.4", 28 | "mpd": "^1.3.0", 29 | "kodi-ws": "^2.3.0" 30 | }, 31 | "repository": { 32 | "type": "git", 33 | "url": "https://github.com/openhybrid/object" 34 | }, 35 | "devDependencies": { }, 36 | "scripts": { 37 | "test": "echo \"Error: no test specified\" && exit 1", 38 | "start": "node server.js" 39 | }, 40 | "author": { 41 | "name": "Valentin Heun", 42 | "email": "heun@media.mit.edu" 43 | }, 44 | "contributors": [ 45 | { 46 | "name": "Shunichi Kasahara", 47 | "email": "" 48 | }, 49 | { 50 | "name": "James Hobin", 51 | "email": "" 52 | }, 53 | { 54 | "name": "Kevin Wong", 55 | "email": "" 56 | }, 57 | { 58 | "name": "Kenny Friedman", 59 | "email": "" 60 | }, 61 | { 62 | "name": "Michelle Suh", 63 | "email": "" 64 | }, 65 | { 66 | "name": "Benjamin F Reynolds ", 67 | "email": "" 68 | }, 69 | { 70 | "name": "Eva Stern-Rodriguez", 71 | "email": "" 72 | }, 73 | { 74 | "name": "Carsten Strunk", 75 | "email": "" 76 | } 77 | ], 78 | "license": "MPL-2.0" 79 | } 80 | --------------------------------------------------------------------------------