├── LICENSE ├── README.md ├── bin └── thc.tcl ├── config.example.tcl ├── developper └── doc │ ├── Generate_HTML.bat │ ├── Generate_MD.bat │ ├── Menu.txt │ ├── THC-Basics.txt │ ├── THC-Developers.txt │ ├── THC-Getting-started.txt │ ├── THC-Introduction.txt │ ├── _nd2md.settings │ ├── nd2md │ ├── _nd2md.language_defs │ ├── _nd2md.settings │ └── nd2md.tcl │ ├── thc_Web.gif │ └── thc_doc_style.css ├── libs ├── pkgIndex.tcl └── t2ws │ ├── LICENSE │ ├── README.md │ ├── pkgIndex.tcl │ ├── t2ws.tcl │ ├── t2ws_bauth.tcl │ └── t2ws_template.tcl ├── modules ├── thc_Csv.tcl ├── thc_HttpDServer │ ├── TclConsole.css │ ├── TclConsole.html │ ├── TclConsole.js │ └── thc_HttpDServer.tcl ├── thc_MailAlert.tcl ├── thc_MeteoSwiss.tcl ├── thc_MultiBinarySwitch.tcl ├── thc_OpenWeatherMap.tcl ├── thc_RandomLight.tcl ├── thc_Rrd │ ├── RrdManip.tcl │ └── thc_Rrd.tcl ├── thc_Timer │ ├── thc_Timer.tcl │ └── thc_Web │ │ ├── thc_Web_API.tcl │ │ ├── www_jqmobile │ │ ├── index.html │ │ ├── jquery.datetimepicker.css │ │ ├── jquery.datetimepicker.js │ │ └── thc_Timer.js │ │ └── www_simple │ │ ├── index.html │ │ ├── jquery.datetimepicker.css │ │ ├── jquery.datetimepicker.js │ │ ├── thc_Timer.css │ │ └── thc_Timer.js ├── thc_Virtual.tcl ├── thc_WavePlusBridge.tcl ├── thc_Web │ ├── index.html │ ├── thc_Web.tcl │ ├── thc_Web_API.tcl │ ├── www_jqmobile │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── thc_Web.css │ │ ├── thc_Web.js │ │ └── thc_jqmobile_themes.css │ └── www_simple │ │ ├── favicon.ico │ │ ├── favicon.xcf │ │ ├── index.html │ │ ├── thc_Web.css │ │ ├── thc_Web.js │ │ ├── thc_Web_ColorBlue.css │ │ ├── thc_Web_ColorDarkGray.css │ │ └── thc_Web_mobile.css └── thc_zWay │ ├── thc_zWay.js │ └── thc_zWay.tcl └── targets └── Raspberry ├── Raspberry-installation.txt ├── install_thc.sh ├── thc.sh └── thc_shell_control.tcl /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Andreas Drollinger 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 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, 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 THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **THC**, **Tight Home Control**, provides a multi-protocol and manufacturer-independent automation framework that allows running control tasks, like for example for home automation. 2 | 3 | THC has the following features : 4 | 5 | * Flexible automation solution - High flexibility through the Tcl scripting language and powerful job definitions 6 | * Target device independent - THC provides a standardized way to access and control various types of target devices: z-Way/Razberry (Z-Wave controller), OpenWeatherMap (access to weather data), MeteoSwiss (access to weather data). 7 | * Rich features set - Responsive web interface, mail alert, random light control, device status and activity logging and plotting, action timer, ... 8 | * Modularity - Support for other target devices, or more features can be added via new modules. 9 | * Platform independent - THC can be installed on each platform that runs Tcl (version 8.5 or higher). 10 | * Low resource needs - THC requires only about 2% CPU time on a on Raspberry PI version 1 (for a setup with 20 devices) 11 | 12 | A web interface provides an optimal experience on desktop and mobile devices. 13 | 14 | ![THC web interface](https://github.com/Drolla/thc/blob/master/developper/doc/thc_Web.gif) 15 | 16 | While the users can perform control operations via the web interface the setup of THC is made via a configuration file that is based on Tcl syntax. THC is in fact entirely programmed in Tcl. Having some basic knowledge of this scripting language is an advantage for the creation of the configuration file. 17 | 18 | 19 | ### What's next 20 | 21 | Start exploring the documentation resources for THC. 22 | 23 | * [THC - Getting started](https://github.com/Drolla/thc/wiki/THC-Getting-started) provides instructions for the installation and configuration of THC on your own computer. 24 | * [THC - Basics](https://github.com/Drolla/thc/wiki/THC-Basics) provides some basics about the way THC works and how to handle device states and events. 25 | * [THC - Core functions](https://github.com/Drolla/thc/wiki/THC-Core-functions) provides documentation for the THC core functions. 26 | * [THC - Developers](https://github.com/Drolla/thc/wiki/THC-Developers) provides information for developers that write THC modules or that contribute to the evolution of THC. 27 | * [THC - Index](https://github.com/Drolla/thc/wiki/THC-Index) provides an index to the different documentation pages and API procedures. 28 | * [THC - Version 2](https://github.com/Drolla/thc/wiki/THC-Version-2) provides information about the internal changes between THC version 1 to 2 and a migration guide for the user configuration scripts. 29 | * [THC - Raspberry PI](https://github.com/Drolla/thc/wiki/Target-Raspberry-installation) THC installation on a Raspberry PI. 30 | -------------------------------------------------------------------------------- /config.example.tcl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Drolla/thc/e94180857c0d43f48d0e93b2b46798d7f5e4a7be/config.example.tcl -------------------------------------------------------------------------------- /developper/doc/Generate_HTML.bat: -------------------------------------------------------------------------------- 1 | :::::::::::::::::::::::::::::::::: 2 | :: Generate HTML Documentation with NaturalDocs 3 | :::::::::::::::::::::::::::::::::: 4 | :: 5 | :: To generate the HTML documentation NaturalDocs and Perl need to be installed 6 | :: and the NaturalDocs launch command specified below. The location where the 7 | :: generated HTML documentation will be stored can also be specified below. 8 | :: 9 | :::::::::::::::::::::::::::::::::: 10 | 11 | :: Specify the NaturalDocs launch command. Examples: 12 | :: set NaturalDocsCommand=perl "C:\Program Files\NaturalDocs\NaturalDocs" 13 | :: set NaturalDocsCommand="C:\Program Files (86)\Perl\bin\perl.exe "C:\Program Files\NaturalDocs\NaturalDocs" 14 | set NaturalDocsCommand="C:\Program Files (x86)\Perl\bin\perl" "..\..\..\..\..\NaturalDocs\NaturalDocs" 15 | 16 | :: Specify the HTML documentation target directory. Examples: 17 | :: set DestinationDir = "..\..\doc" 18 | set DestinationDir="..\..\doc" 19 | 20 | ::::::::::::::::::::::::::::::::::::: 21 | 22 | 23 | %NaturalDocsCommand% ^ 24 | --project "." ^ 25 | --source "." ^ 26 | --source "..\..\bin" ^ 27 | --source "..\..\modules" ^ 28 | --source "..\..\targets" ^ 29 | --exclude-source "..\..\modules\thc_Web\www_jmobile" ^ 30 | --output HTML %DestinationDir% ^ 31 | -s "Default thc_doc_style" 32 | -------------------------------------------------------------------------------- /developper/doc/Generate_MD.bat: -------------------------------------------------------------------------------- 1 | :::::::::::::::::::::::::::::::::: 2 | :: Generate MarkDown Documentation 3 | :::::::::::::::::::::::::::::::::: 4 | :: 5 | :: Specify the destination directory and documentation file definitions inside 6 | :: the file _nd2md.settings: 7 | :: 8 | :: set nd2md_DestDir 9 | :: array set nd2md_nd2md { 10 | :: 11 | :: 12 | :: ... ... 13 | :: } 14 | :: 15 | :: Example: 16 | :: 17 | :: set nd2md_DestDir "../../../thc.wiki" 18 | :: array set nd2md_nd2md { 19 | :: ../../bin/thc.tcl {THC-Core-functions.md} 20 | :: } 21 | :: 22 | :::::::::::::::::::::::::::::::::: 23 | 24 | :: General documentation 25 | tclsh nd2md\nd2md.tcl ^ 26 | "THC-Introduction.txt" ^ 27 | "THC-Getting-started.txt" ^ 28 | "THC-Basics.txt" ^ 29 | "THC-Developers.txt" ^ 30 | "THC-Version-2.txt" 31 | 32 | :: Core function documentation 33 | tclsh nd2md\nd2md.tcl ../../bin/thc.tcl 34 | 35 | :: Module documentation 36 | tclsh nd2md\nd2md.tcl ^ 37 | ../../modules/thc_MailAlert.tcl ^ 38 | ../../modules/thc_HttpDServer/thc_HttpDServer.tcl ^ 39 | ../../modules/thc_MeteoSwiss.tcl ^ 40 | ../../modules/thc_OpenWeatherMap.tcl ^ 41 | ../../modules/thc_RandomLight.tcl ^ 42 | ../../modules/thc_Virtual.tcl ^ 43 | ../../modules/thc_WavePlusBridge.tcl ^ 44 | ../../modules/thc_MultiBinarySwitch.tcl ^ 45 | ../../modules/thc_Rrd/thc_Rrd.tcl ^ 46 | ../../modules/thc_Rrd/RrdManip.tcl ^ 47 | ../../modules/thc_Timer/thc_Timer.tcl ^ 48 | ../../modules/thc_Web/thc_Web.tcl ^ 49 | ../../modules/thc_zWay/thc_zWay.tcl ^ 50 | ../../modules/thc_Csv.tcl 51 | 52 | :: Other documentation 53 | tclsh nd2md\nd2md.tcl ../../targets/Raspberry/Raspberry-installation.txt 54 | tclsh nd2md\nd2md.tcl ../../modules/thc_Web/thc_Web_API.tcl 55 | tclsh nd2md\nd2md.tcl -n ../../modules/thc_zWay/thc_zWay.js 56 | 57 | :: Generate the index file 58 | tclsh nd2md\nd2md.tcl -x 59 | 60 | :: Copy the used images to the destination 61 | copy thc_Web.gif ..\..\..\thc.wiki -------------------------------------------------------------------------------- /developper/doc/Menu.txt: -------------------------------------------------------------------------------- 1 | Format: 1.52 2 | 3 | 4 | # You can add a title and sub-title to your menu like this: 5 | # Title: [project name] 6 | # SubTitle: [subtitle] 7 | 8 | # You can add a footer to your documentation like this: 9 | # Footer: [text] 10 | # If you want to add a copyright notice, this would be the place to do it. 11 | 12 | # You can add a timestamp to your documentation like one of these: 13 | # Timestamp: Generated on month day, year 14 | # Timestamp: Updated mm/dd/yyyy 15 | # Timestamp: Last updated mon day 16 | # 17 | # m - One or two digit month. January is "1" 18 | # mm - Always two digit month. January is "01" 19 | # mon - Short month word. January is "Jan" 20 | # month - Long month word. January is "January" 21 | # d - One or two digit day. 1 is "1" 22 | # dd - Always two digit day. 1 is "01" 23 | # day - Day with letter extension. 1 is "1st" 24 | # yy - Two digit year. 2006 is "06" 25 | # yyyy - Four digit year. 2006 is "2006" 26 | # year - Four digit year. 2006 is "2006" 27 | 28 | 29 | # -------------------------------------------------------------------------- 30 | # 31 | # Cut and paste the lines below to change the order in which your files 32 | # appear on the menu. Don't worry about adding or removing files, Natural 33 | # Docs will take care of that. 34 | # 35 | # You can further organize the menu by grouping the entries. Add a 36 | # "Group: [name] {" line to start a group, and add a "}" to end it. 37 | # 38 | # You can add text and web links to the menu by adding "Text: [text]" and 39 | # "Link: [name] ([URL])" lines, respectively. 40 | # 41 | # The formatting and comments are auto-generated, so don't worry about 42 | # neatness when editing the file. Natural Docs will clean it up the next 43 | # time it is run. When working with groups, just deal with the braces and 44 | # forget about the indentation and comments. 45 | # 46 | # You can use this file on other computers even if they use different 47 | # directories. As long as the command line points to the same source files, 48 | # Natural Docs will be able to correct the locations automatically. 49 | # 50 | # -------------------------------------------------------------------------- 51 | 52 | 53 | File: THC - Getting started (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\developper\doc\THC-Getting-started.txt) 54 | File: THC - Introduction (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\developper\doc\THC-Introduction.txt) 55 | File: Core functions (no auto-title, C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\bin\thc.tcl) 56 | File: THC - Basics (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\developper\doc\THC-Basics.txt) 57 | 58 | Group: Target interface modules { 59 | 60 | File: HTTP debug server (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\modules\thc_HttpDServer\thc_HttpDServer.tcl) 61 | File: MeteoSwiss (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\modules\thc_MeteoSwiss.tcl) 62 | File: Multi binary switch devices (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\modules\thc_MultiBinarySwitch.tcl) 63 | File: OpenWeatherMap (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\modules\thc_OpenWeatherMap.tcl) 64 | File: Status logging in CSV format (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\modules\thc_Csv.tcl) 65 | File: Virtual devices (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\modules\thc_Virtual.tcl) 66 | File: Wave Plus Bridge interface (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\modules\thc_WavePlusBridge.tcl) 67 | File: z-Way/Razberry interface (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\modules\thc_zWay\thc_zWay.tcl) 68 | } # Group: Target interface modules 69 | 70 | Group: Extension modules { 71 | 72 | File: Job timer (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\modules\thc_Timer\thc_Timer.tcl) 73 | File: Mail alert (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\modules\thc_MailAlert.tcl) 74 | File: Random light control (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\modules\thc_RandomLight.tcl) 75 | File: Status logging and graph generation (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\modules\thc_Rrd\thc_Rrd.tcl) 76 | File: Web interface (no auto-title, C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\modules\thc_Web\thc_Web.tcl) 77 | } # Group: Extension modules 78 | 79 | Group: Targets { 80 | 81 | File: THC installation on a Raspberry PI (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\targets\Raspberry\Raspberry-installation.txt) 82 | } # Group: Targets 83 | 84 | Group: Utilities { 85 | 86 | File: THC RRD database manipulation utility (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\modules\thc_Rrd\RrdManip.tcl) 87 | } # Group: Utilities 88 | 89 | Group: Developers { 90 | 91 | File: THC - Developers (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\developper\doc\THC-Developers.txt) 92 | File: Web server API (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\modules\thc_Web\thc_Web_API.tcl) 93 | File: z-Way extension for THC (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\modules\thc_zWay\thc_zWay.js) 94 | } # Group: Developers 95 | 96 | File: nd2md - NaturalDocs to MarkDown translator (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\developper\doc\nd2md\nd2md.tcl) 97 | File: THC - Version 2 (C:\Users\Andreas Drollinger\Development\Tcl\_My Apps\thc\developper\doc\THC-Version-2.txt) 98 | 99 | Group: Index { 100 | 101 | Index: Everything 102 | Function Index: Functions 103 | } # Group: Index 104 | 105 | 106 | 107 | ##### Do not change or remove these lines. ##### 108 | Data: 1(D3330wba6GH6bK\fHGp6XBHuoo8\`GHbBG/GouIEG\tbL9obVPQXKII6btR9bfG/GouIIGHbfu9) 109 | Data: 1(h3330wba6GH6bK\fHGp6XBHuoo8\`GHbBG/GouIEG\tbL9obVPQXKII6btR9bY8\) 110 | Data: 1(T3330wba6GH6bK\fHGp6XBHuoo8\`GHbBG/GouIEG\tbL9obVPQXKII6btR9bEufNoG6) 111 | Data: 1(-3330wba6GH6bK\fHGp6XBHuoo8\`GHbBG/GouIEG\tbL9obVPQXKII6btR9btpH`Gt6) 112 | -------------------------------------------------------------------------------- /developper/doc/THC-Basics.txt: -------------------------------------------------------------------------------- 1 | Title: THC - Basics 2 | 3 | 4 | Topic: Main control loop 5 | 6 | Once THC completed the setup phase it enters forever into the main control loop. 7 | In an interval defined by *thc::HeartBeatMS* the following sequence is executed: 8 | * The device states and device events are updated 9 | * The jobs scheduled for the current time are executed 10 | 11 | 12 | Topic: Device states and events 13 | 14 | Each heartbeat interval the device states and device events are updated. The 15 | device state is available for custom scripts and tasks via the *thc::State* 16 | array variable: 17 | > thc::State() 18 | Example: 19 | > puts $thc::State(Siren,state) 20 | > -> 0 21 | > puts $thc::State(MotionLiving,battery) 22 | > -> 80 23 | 24 | The *thc::Event* array variable that is also updated every heartbeat will 25 | contain during a single heartbeat interval the state value of a device if the 26 | state is switched to a new valid value (non ""). Transitions from and to non 27 | valid values ("") are filtered: A transition from an initial state value to an 28 | invalid value ("") and back to the initial value will not generate an event. 29 | However a transition from a first value to an invalid value, and then to a last 30 | value that is different from the first value, will generate an event. 31 | > _____???_____???-------???----???_________---------________ 32 | > ^ ^ ^ ^ 33 | > |Event=1 |Event=0 |Event=1 |Event=0 34 | Example: 35 | > thc::DefineJob -tag Surv -description "Surveillance" { 36 | > if {$thc::Event(MySensor)==1} { 37 | > thc::Set {Sirene,state LightLiving,state} 1 } 38 | > } 39 | 40 | Finally, for devices that have been declared with the *-sticky* option 41 | (see ) the first occurring device state that is valid and 42 | non-zero is also stored in the array variable *thc::StickyState*. The sticky 43 | state variable can be cleared with the command , which needs 44 | to be called by a custom job. 45 | 46 | The sticky state variable allows capturing over a certain period the 47 | occurrence of an event, to log the event then by a longer interval job. Logging 48 | functions like log typically the sticky state values instead of 49 | the instantaneous state, for devices that have a sticky state. Example: 50 | 51 | > thc::DefineJob -tag RrdLog -time +1m -repeat 1m -description "RRD log" { 52 | > thc::Rrd::Log 53 | > thc::ResetStickyStates } 54 | -------------------------------------------------------------------------------- /developper/doc/THC-Developers.txt: -------------------------------------------------------------------------------- 1 | Title: THC - Developers 2 | 3 | This page provides information for developers that write THC modules or that contribute to the evolution of THC. 4 | 5 | 6 | Topic: Modules 7 | 8 | Single Tcl file modules can directly be stored inside the folder *modules*. Modules that have multiple files should have a dedicated sub-folder that is placed inside *modules*. 9 | 10 | For that modules are automatically loaded during initialization, the module Tcl names have to follow the following name convention: thc_.tcl. The name of dedicated module sub-directories need to follow the following convention: thc_. 11 | 12 | Modules should use their dedicated namespace ::thc::. Target interface modules allow accessing devices of a specific target via the following standard functions: 13 | 14 | Init - Optional, allows initializing the target. This command is not 15 | automatically called, but needs to be called from the 16 | configuration file. 17 | DeviceSetup - Optional, is called when a new device is registered 18 | by . The 'get' command specification of the device 19 | is provided as argument to 'DeviceSetup'. 20 | Get - Has to return the states of a list of devices. The 'get' 21 | commands for the device list is provided as argument. If a device 22 | state is not available 'Get' has to return an empty string (""). 23 | Set - Hast to set the states of a list of devices. 24 | the 'set' commands for the device list, as well as the new common 25 | state for all devices, are provided as arguments. 26 | 27 | The 'get' and 'set' commands are derived from the command specifications provided to the command. This is illustrated using the zWay module as example. 28 | 29 | The configuration file contains an explicitly initialization of the z-way interface : 30 | 31 | > thc::zWay::Init "http://localhost:8083" 32 | 33 | The configuration file also registers 2 zWay devices : 34 | 35 | > thc::DefineDevice LightLiving,state -get {thc_zWay "SwitchBinary 8.1"} \ 36 | > -set {thc_zWay "SwitchBinary 8.1"} 37 | > thc::DefineDevice LightEntry,state -get {thc_zWay "SwitchBinary 9.2"} \ 38 | > -set {thc_zWay "SwitchBinary 9.2"} 39 | 40 | The command calls 'DeviceSetup' of the relevant module, providing as argument the 'get' command specification: 41 | 42 | > thc::zWay::DeviceSetup "SwitchBinary 8.1" 43 | > thc::zWay::DeviceSetup "SwitchBinary 9.2" 44 | 45 | When the states of all devices are updated every heartbeat, the 'Get' command of the module is called with a list of 'get' command specifications for all devices. The 'Get' command of the module has to return the list of the device states. In the following example the states of 2 devices is read. 46 | 47 | > thc::zWay::Get {"SwitchBinary 8.1" "SwitchBinary 9.2"} 48 | 49 | Devices states are defined with the command, that accepts a list of devices to set: 50 | 51 | > thc::Set {LightLiving,state LightEntry,state} 1 52 | 53 | The command calls the Set command of the module, providing as argument the list of 'set' command specifications: 54 | 55 | > thc::zWay::Set {"SwitchBinary 8.1" "SwitchBinary 9.2"} 1 56 | 57 | -------------------------------------------------------------------------------- /developper/doc/THC-Getting-started.txt: -------------------------------------------------------------------------------- 1 | Title: THC - Getting started 2 | 3 | This document provides instructions for the installation and configuration of THC on your computer. 4 | 5 | Topics: Requirements 6 | 7 | THC requires that Tcl 8.5 or above is installed on the target system. The Tk extension is not required to run THC. 8 | 9 | To log device states and to plot graphs either the standalone RRD tools or the RRD package for Tcl needs to be installed. 10 | 11 | 12 | Topics: Installing THC 13 | 14 | The full THC package should be stored at a location from where the THC program can be executed. On Unix derived systems this may be /opt, but it can also be another location. The THC main program (bin/thc.tcl) needs to be executable (e.g. Run on Unix: _chmod 775 bin/thc.tcl_). 15 | 16 | On Unix derived systems THC can be configured as service to start it automatically each time the system boots. 17 | 18 | See also: 19 | 20 | 21 | Topics: Configuring THC 22 | 23 | THC requires the configuration file *config.tcl* that is usually stored inside the THC main directory. This configuration file declares devices and automation tasks (jobs). An example configuration file is placed in the THC main directory. It provides a good starting point to write a customized configuration file. Read also the documentation to get some basics about the way to handle device states and events. This information is required for the declaration of jobs. 24 | 25 | * Heartbeat definition: The heartbeat defines the update interval in milliseconds. The default update interval is 1000ms. 26 | > thc::DefineHeartBeat 1000 MS 27 | 28 | * Specify a log file and a log level (level: 0 - very detailed log, 3 - log of important messages, see also ) 29 | > thc::DefineLog 1 "/var/thc/thc_server.log" 1 30 | 31 | * Start the HTTP web server by providing the TCP/IP port to use 32 | > thc::Web::Start 8086 33 | 34 | * If you use a z-Way/Razberry controller, define the z-Way server access IP port (see ) 35 | > thc::zWay::Init "http://localhost:8083" 36 | 37 | * Declare your devices (see ) 38 | > # Virtual devices 39 | > thc::DefineDevice Surveillance,state \ 40 | > -name Surveillance -group Scenes -type switch \ 41 | > -get {thc_Virtual "Surveillance"} \ 42 | > -set {thc_Virtual "Surveillance"} 43 | > 44 | > # Z-Way devices 45 | > thc::DefineDevice MotionLiving,state -get {thc_zWay "SensorBinary 12"} -sticky 1 46 | > thc::DefineDevice Sirene,state -get {thc_zWay "SwitchBinary 16.0"} \ 47 | > -set {thc_zWay "SwitchBinary 16.0"} 48 | > thc::DefineDevice LightLiving,state -get {thc_zWay "SwitchBinary 8.1"} \ 49 | > -set {thc_zWay "SwitchBinary 8.1"} 50 | > 51 | > # OpenWeatherMap devices 52 | > thc::DefineDevice ChauxDeFonds,temp \ 53 | > -name Bern -group Environment -format "%sC" -range {-30 50} -update 10m \ 54 | > -get {thc_OpenWeatherMap {"Bern,ch" "temp"}} 55 | > 56 | > # OpenWeatherMap devices 57 | > thc::DefineDevice ChauxDeFonds,chx_hum \ 58 | > -name "Humidity Chaux-de-Fonds" -group Environment -format "%s%%" -update 10m \ 59 | > -get {thc_MeteoSwiss {"CDF" "humidity"}} 60 | 61 | * Automation tasks/jobs definitions (see ) 62 | > thc::DefineJob -tag Surv -description "Alarm detection" \ 63 | > -condition {$Event(Alarm,state)==1} { 64 | > 65 | > thc::Set {Sirene,state LightLiving,state} 1 66 | > thc::Log "Alarm on" 1 67 | > 68 | > thc::DefineJob -tag SirenOff -description "Stop the alarm siren" -time +3m { 69 | > thc::Set Sirene,state 0 70 | > thc::Log "Alarm siren stopped" 1 71 | > } 72 | > 73 | > thc::DefineJob -tag LightOff -description "Switch off the alarm lights" -time +45m { 74 | > thc::Set LightLiving,state 0 75 | > thc::Log "Alarm lights turned off" 1 76 | > } 77 | > } 78 | 79 | Please refer to the documentation of the different extension modules to get information about module specific configurations. 80 | 81 | Topics: Start THC 82 | 83 | Before you run THC, make sure that the THC main program is executable (on Unix like systems) and that the log directory exists (e.g. /var/thc). If the Tcl interpreter executable is named 'tclsh' THC can be directly launched with the following command : 84 | > /bin/thc.tcl [Options] 85 | 86 | Otherwise mention in the command line explicitly the Tcl interpreter command : 87 | > /bin/thc.tcl [Options] 88 | 89 | The options have to be pairs of THC internal variable names prefixed with '-' and the corresponding variable initialization values. The following variables may be changed : 90 | 91 | DebugScript - Allows defining a debug script file that will be executed 92 | after loading the modules, but before the configuration file is executed. 93 | ConfigFile - Configuration file. The default configuration file is 94 | 'config.tcl' that is stored inside the THC root directory. 95 | 96 | Example : 97 | > tclsh thc.tcl -DebugScript ThcDebug.tcl 98 | 99 | 100 | Topics: Go test THC! 101 | 102 | If you started in your configuration file a web server you can now open in your preferred web browser the THC website. The default web interface should be compatible with any newer browsers. To point your browser to the THC website, enter as URL : 103 | 104 | > http://: 105 | -------------------------------------------------------------------------------- /developper/doc/THC-Introduction.txt: -------------------------------------------------------------------------------- 1 | Title: THC - Introduction 2 | 3 | THC, Tight Home Control, provides a multi-protocol and manufacturer-independent 4 | automation framework that allows running control tasks, like for example for home automation. 5 | 6 | THC has the following features : 7 | 8 | Flexible automation solution - High flexibility through the Tcl scripting language and powerful job definitions 9 | Target device independent - THC provides a standardized way to access and control various types of target devices: z-Way/Razberry (Z-Wave controller), OpenWeatherMap (access to weather data), MeteoSwiss (access to weather data). 10 | Rich features set - Responsive web interface, mail alert, random light control, device status and activity logging and plotting, action timer, ... 11 | Modularity - Support for other target devices, or more features can be added via new modules. 12 | Platform independent - THC can be installed on each platform that runs Tcl (version 8.5 or higher). 13 | Low resource needs - THC requires only about 2% CPU time on a on Raspberry PI version 1 (for a setup with 20 devices) 14 | 15 | A web interface provides an optimal experience on desktop and mobile devices : 16 | 17 | (see thc_Web.gif) 18 | 19 | While the users can perform control operations via the web interface the setup of THC is made via a configuration file that is based on Tcl syntax. THC is in fact entirely programmed in Tcl. Having some basic knowledge of this scripting language is an advantage for the creation of the configuration file. 20 | 21 | 22 | Next steps: 23 | 24 | Start exploring the documentation resources for THC. 25 | 26 | * provides instructions for the installation and configuration of THC on your own computer. 27 | * provides some basics about the way THC works and how to handle device states and events. 28 | * provides documentation for the THC core functions. 29 | * provides information for developers that write THC modules or that contribute to the evolution of THC. 30 | * provides information about the internal changes from THC version 1 to 2 and a migration guide for the user configuration scripts. 31 | * THC installation on a Raspberry PI. 32 | -------------------------------------------------------------------------------- /developper/doc/_nd2md.settings: -------------------------------------------------------------------------------- 1 | set nd2md_DestDir "../../../thc.wiki" 2 | 3 | array set nd2md_nd2md { 4 | ../../bin/thc.tcl {THC-Core-functions.md} 5 | ../../modules/thc_zWay/thc_zWay.js {zWay-JS-Extension.md} 6 | ../../modules/thc_Rrd/RrdManip.tcl {Tool-RrdManip.md} 7 | } 8 | 9 | array set nd2md_config { 10 | index_file "THC-Index.md" 11 | index_file_title "THC - Index" 12 | deflist_mapping "table" 13 | } -------------------------------------------------------------------------------- /developper/doc/nd2md/_nd2md.language_defs: -------------------------------------------------------------------------------- 1 | # Tcl 2 | array set LanguageDefs { 3 | tcl,LineCommentPattern {\s*#\s*(.*)} 4 | tcl,MultiLineCommentStartPattern {} 5 | tcl,MultiLineCommentEndPattern {} 6 | } 7 | 8 | # Txt 9 | array set LanguageDefs { 10 | txt,LineCommentPattern {(.*)} 11 | txt,MultiLineCommentStartPattern {} 12 | txt,MultiLineCommentEndPattern {} 13 | } 14 | 15 | # JS (JavaScript) 16 | array set LanguageDefs { 17 | js,LineCommentPattern {\s*//\s*(.*)} 18 | js,MultiLineCommentStartPattern {^\s*/\*[\\*-=_]*\s*(.*?)$} 19 | js,MultiLineCommentEndPattern {^(.*?)[\\*-=_]*/\s*$} 20 | } 21 | 22 | -------------------------------------------------------------------------------- /developper/doc/nd2md/_nd2md.settings: -------------------------------------------------------------------------------- 1 | array set nd2md_config { 2 | index_file "Index.md" 3 | index_file_title "Index" 4 | deflist_mapping "table" 5 | } 6 | 7 | set nd2md_DestDir "md_docs" 8 | 9 | set nd2md_regsub {} 10 | 11 | array set nd2md_nd2md { 12 | } 13 | 14 | array set nd2md_Link {} 15 | -------------------------------------------------------------------------------- /developper/doc/nd2md/nd2md.tcl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # the next line restarts using tclsh \ 3 | exec tclsh "$0" ${1+"$@"} 4 | ########################################################################## 5 | # nd2md.tcl - Natural Docs to MarkDown converter 6 | # 7 | # This program reads files that contain documentation in the Natural Docs 8 | # syntax, and generates the corresponding documents in the GitHub 9 | # MarkDown syntax. 10 | # 11 | # Copyright (C) 2015/2016 Andreas Drollinger 12 | ########################################################################## 13 | # See the file "LICENSE" for information on usage and redistribution 14 | # of this file, and for a DISCLAIMER OF ALL WARRANTIES. 15 | ########################################################################## 16 | 17 | # Title: nd2md - NaturalDocs to MarkDown translator 18 | 19 | 20 | 21 | # Build and return from a link text the MD link. 22 | proc GetLink {LinkText {LinkFile ""}} { 23 | global nd2md_Link 24 | set Link $LinkText 25 | if {[info exists nd2md_Link($Link)]} { 26 | set LkFile [lindex $nd2md_Link($Link) 1] 27 | if {$LkFile==$LinkFile} { 28 | set LkFile ""} 29 | set LkSection [string tolower [lindex $nd2md_Link($Link) 2]] 30 | regsub -all {:} $LkSection {} LkSection 31 | regsub -all { } $LkSection {-} LkSection 32 | set Link "$LkFile\#$LkSection" 33 | } 34 | return $Link 35 | } 36 | 37 | # Parse the NaturalDoc documentation in a file, and generate the corresponding 38 | # MarkDown file. 39 | proc nd2md {NdFile MdFile LinkFile Format} { 40 | global LanguageDefs nd2md_Link nd2md_config CreateReferenceIndexes 41 | 42 | # Check the language definitions 43 | foreach Pattern {LineCommentPattern MultiLineCommentStartPattern MultiLineCommentEndPattern} { 44 | if {![info exists LanguageDefs($Format,$Pattern)]} { 45 | puts stdout "File format '$Format' is not defined!" 46 | exit 1 47 | } 48 | } 49 | 50 | # Read the Natural Docs file 51 | set f [open $NdFile] 52 | set Data [read $f] 53 | close $f 54 | 55 | # Start parsing the file 56 | set Mode "" 57 | set SubMode "" 58 | set Section "^"; # Page begin 59 | set MdFileContent "" 60 | set LinkList {} 61 | set ActiveCommentSection 0 62 | foreach Line [split $Data "\n"] { 63 | set MdLine "" 64 | set AppendMdLine 0 65 | set NewSection "" 66 | 67 | set DocText "" 68 | set IsDocText 0 69 | if {!$ActiveCommentSection} { 70 | if {[regexp $LanguageDefs($Format,LineCommentPattern) $Line {} DocText]} { 71 | set IsDocText 1 72 | } elseif {$LanguageDefs($Format,MultiLineCommentStartPattern)!="" && [regexp $LanguageDefs($Format,MultiLineCommentStartPattern) $Line {} DocText]} { 73 | set IsDocText 1 74 | set ActiveCommentSection 1 75 | } 76 | } else { # $ActiveCommentSection 77 | set IsDocText 1 78 | if {[regexp $LanguageDefs($Format,MultiLineCommentEndPattern) $Line {} DocText]} { 79 | set ActiveCommentSection 0 80 | } else { 81 | set DocText $Line 82 | } 83 | } 84 | 85 | if {!$IsDocText} { 86 | set Mode "" 87 | set SubMode "" 88 | } else { 89 | set RowDocText [string trim $DocText] 90 | regsub -all {<} $RowDocText {\\<} DocText 91 | if {$DocText=="" || [string trim $DocText "\#"]==""} { 92 | set NewSection "" 93 | } elseif {[regexp {Title\s*:\s*(.+)} $DocText {} Title]} { 94 | set MdLine "\# $Title" 95 | set Mode Title 96 | set NewSection Title 97 | set nd2md_Link($Title) [list title $LinkFile $Title] 98 | } elseif {[regexp {Group\s*:\s*(.+)} $DocText {} Group] | 99 | [regexp {Topics{0,1}\s*:\s*(.+)} $DocText {} Group]} { 100 | if {[regexp {Group\s*:\s*(.+)} $DocText]} { 101 | set MdLine "\#\# $Group" 102 | } else { 103 | set MdLine "\#\#\# $Group" 104 | } 105 | set Mode Group 106 | set NewSection Group 107 | if {$CreateReferenceIndexes} { 108 | set nd2md_Link($Group) [list group $LinkFile $Group] 109 | } 110 | } elseif {[regexp {((Proc)|(Function))\s*:\s*(.+)} $DocText {} ProcOrFunc {} {} Proc]} { 111 | set MdLine "***\n\#\#\# $ProcOrFunc: $Proc" 112 | set Mode Proc 113 | set NewSection Proc 114 | if {$CreateReferenceIndexes} { 115 | set nd2md_Link($Proc) [list proc $LinkFile "proc-$Proc"] 116 | } 117 | } elseif {[regexp {Var\s*:\s*(.+)} $DocText {} Var]} { 118 | set MdLine "***\n\#\#\# Var: $Var" 119 | set Mode Var 120 | set NewSection Var 121 | if {$CreateReferenceIndexes} { 122 | set nd2md_Link($Var) [list proc $LinkFile "var-$Var"] 123 | } 124 | } elseif {$Mode=="Proc" && $Section=="" && [regexp {(.*[^\s]):\s*$} $DocText {} SubMode]} { 125 | set MdLine "\#\#\#\# $SubMode" 126 | set NewSection ProcSectionTitle 127 | } elseif {$Mode!="" && [regexp {^[>:|](.*)$} $RowDocText {} Code]} { 128 | set NewSection Code 129 | set MdLine $Code 130 | } elseif {$Mode!=""} { 131 | regsub -all {\|} $DocText {\\|} DocTextT 132 | 133 | # Handle links 134 | set LinkList2 {} 135 | foreach {LinkInsertPos LinkPos} [lreverse [regexp -inline -indices -all {[^\w](\\<[^\s][^!?*<>|\"]*[^\s]>)[^\w]} " $DocText "]] { 136 | set Link [string range $DocText [lindex $LinkPos 0]+2 [lindex $LinkPos 1]-3] 137 | lappend LinkList2 $Link 138 | set DocText [string replace $DocText [expr {[lindex $LinkPos 0]+0}] [expr {[lindex $LinkPos 1]-2}] "\[$Link\]"] 139 | } 140 | 141 | # Handle images 142 | foreach {PictFilePos PictInsertPos} [lreverse [regexp -inline -indices -all {\(see\s+([^\s\)]+)\)} $DocText]] { 143 | set PictureFile [string range $DocText {*}$PictFilePos] 144 | if {[regexp {\.(gif)|(png)|(jpg)$} $PictureFile]} { 145 | set DocText [string replace $DocText {*}$PictInsertPos "!\[\]($PictureFile)"] 146 | } 147 | } 148 | 149 | if {[regexp {^([-+*][\s].*)$} $DocText {} List]} { 150 | set NewSection List 151 | set MdLine $List 152 | lappend LinkList {*}$LinkList2 153 | } elseif {$Section=="List"} { # Paragraph extension of a list 154 | set MdLine $DocTextT 155 | set AppendMdLine 1; # Append the new line to the previous one 156 | set NewSection List 157 | lappend LinkList {*}$LinkList2 158 | } elseif {[regexp {^(.+?)\s+-\s+(.+)$} $DocTextT {} Col0 Col1]} { # Definition list: Will be transformed in a table 159 | if {$nd2md_config(deflist_mapping)=="table"} { 160 | if {$Section!="DefList"} { 161 | set MdLine "|$SubMode|Description\n|--:|---\n" } 162 | append MdLine "|$Col0|$Col1" 163 | } else { 164 | set MdLine "- **$Col0** : $Col1" 165 | } 166 | set NewSection DefList 167 | } elseif {$Section=="DefList"} { # Paragraph extension of a definition list 168 | set MdLine $DocTextT 169 | set AppendMdLine 1; # Append the new line to the previous one 170 | set NewSection DefList 171 | } elseif {$Section=="" && [regexp {^([^\s].*[^\s]):\s*$} $DocText {} Heading]} { # Heading, only valid if the previous line is empty 172 | set MdLine "\#\#\#\# $Heading" 173 | set NewSection Heading 174 | } else { 175 | regsub -all {^-$} $DocText {\-} DocText 176 | set MdLine $DocText 177 | set NewSection "Paragraph" 178 | lappend LinkList {*}$LinkList2 179 | } 180 | } 181 | } 182 | if {$Section=="Code" && $NewSection!="Code"} { 183 | append MdFileContent "\n```"; # End a code section 184 | } 185 | if {$NewSection!=$Section && $NewSection!="" && $Section!="^"} { 186 | append MdFileContent "\n"; # Add an empty line between the sections 187 | } 188 | 189 | #append MdFileContent "\n[string repeat { } 90]$Mode :: $Section :: $NewSection\n" 190 | if {$MdLine!="" || $NewSection=="Code"} { 191 | if {!$AppendMdLine} { 192 | append MdFileContent "\n" 193 | } elseif {[string index $MdFileContent end]!=""} { 194 | append MdFileContent " " 195 | } 196 | if {$NewSection=="Code" && $Section!="Code"} { 197 | append MdFileContent "```\n"; # Start a code section 198 | } 199 | append MdFileContent $MdLine 200 | } 201 | set Section $NewSection 202 | } 203 | 204 | # Add the link references 205 | append MdFileContent "\n\n" 206 | foreach LinkText [lsort -unique $LinkList] { 207 | append MdFileContent "\[$LinkText\]: [GetLink $LinkText $LinkFile]\n" 208 | } 209 | 210 | # Remove leading empty lines 211 | set MdFileContent [string trimleft $MdFileContent "\n\t "] 212 | 213 | # Apply custom regular expression replacements 214 | foreach RegSubDef $::nd2md_regsub { 215 | regsub -all [lindex $RegSubDef 0] $MdFileContent [lindex $RegSubDef 1] MdFileContent 216 | } 217 | 218 | # Open the MarkDown file, and write the content 219 | set f [open $MdFile w] 220 | puts -nonewline $f $MdFileContent 221 | close $f 222 | } 223 | 224 | # Generate the index file 225 | proc GenIndexFile {MdIndexFile} { 226 | global nd2md_Link 227 | 228 | # Classify all links 229 | array set Links {proc {} doc {}} 230 | foreach {LinkText v} [array get nd2md_Link] { 231 | switch [lindex $v 0] { 232 | "proc" { 233 | set ProcName $LinkText 234 | set ProcNS "" 235 | regexp {^(.*)::(.+?)$} $LinkText {} ProcNS ProcName 236 | lappend Links(proc) [list [list $ProcName $ProcNS] $LinkText] 237 | } 238 | "title" { 239 | lappend Links(doc) [list [list $LinkText ""] $LinkText] 240 | } 241 | } 242 | } 243 | 244 | # Open the Index MarkDown file, and write the content 245 | set f [open $MdIndexFile w] 246 | puts $f "\# $::nd2md_config(index_file_title)" 247 | 248 | 249 | foreach {SectionKey SectionTitle AddSubSections} { 250 | doc "Documents" 0 251 | proc "Procedures" 1 252 | } { 253 | puts $f "\n\## $SectionTitle\n" 254 | set SubSection "" 255 | foreach Link [lsort -index 0 -dictionary $Links($SectionKey)] { 256 | set NsText [lindex $Link 0 1] 257 | if {$NsText!=""} { 258 | set NsText ", $NsText" } 259 | set NewSubSection [string toupper [string index [lindex $Link 0 0] 0]] 260 | if {$AddSubSections && $NewSubSection!=$SubSection} { 261 | puts $f "\n\#### $NewSubSection\n" 262 | set SubSection $NewSubSection } 263 | puts $f " * \[[lindex $Link 0 0]\]([GetLink [lindex $Link end]])$NsText" 264 | } 265 | } 266 | 267 | close $f 268 | } 269 | 270 | # Load the settings and index cache 271 | proc LoadConfigAndIndex {} { 272 | uplevel { 273 | # Load the language definitions. Load first the global and then the local 274 | # definitions 275 | source [file join [file dirname [info script]] "_nd2md.language_defs"] 276 | catch {source "_nd2md.language_defs"} 277 | 278 | # Load the tool settings. Load first the global and then the local 279 | # definitions 280 | source [file join [file dirname [info script]] "_nd2md.settings"] 281 | catch {source "_nd2md.settings"} 282 | 283 | # Load the local doc index 284 | catch {source "_nd2md.index"} 285 | } 286 | } 287 | 288 | # Store the index 289 | proc StoreIndex {} { 290 | global nd2md_Link 291 | set f [open _nd2md.index w] 292 | 293 | puts $f "array set nd2md_Link \{" 294 | foreach {n v} [array get nd2md_Link] { 295 | puts $f " \"$n\" \{$v\}" 296 | } 297 | puts $f "\}" 298 | 299 | close $f 300 | } 301 | 302 | # Load the settings 303 | LoadConfigAndIndex 304 | 305 | # Parse the arguments 306 | # nd2md.tcl 307 | # [-d ] 308 | # [-o ] 309 | # [-f ] 310 | # [-x] - Generate new index MD file 311 | # [-n] - Don't create reference indexes for the file content 312 | # [-config =] - Overrides configuration deined by _nd2md.settings file 313 | # NdFile1 [NdFile2, ...] 314 | set GenIndex 0 315 | set DestDir $nd2md_DestDir 316 | set OutFile "" 317 | set Format "" 318 | set NdFileList {} 319 | set CreateReferenceIndexes 1 320 | for {set a 0} {$a<[llength $argv]} {incr a} { 321 | switch -exact [lindex $argv $a] { 322 | -d {set DestDir [lindex $argv [incr a]]} 323 | -o {set OutFile [lindex $argv [incr a]]} 324 | -f {set Format [lindex $argv [incr a]]} 325 | -x {set GenIndex 1} 326 | -n {set CreateReferenceIndexes 0} 327 | -config { 328 | regexp {^(.*)=(.*)$} [lindex $argv [incr a]] {} CfgName CfgValue 329 | set nd2md_config($CfgName) $CfgValue 330 | } 331 | default {lappend NdFileList [lindex $argv $a]} 332 | } 333 | } 334 | 335 | if {$OutFile!="" && [llength $NdFileList]!=1} { 336 | puts stderr "Exact one NdFile has to be provided if the option -o is defined" 337 | exit 1 338 | } 339 | 340 | # Create the destination directory if not yet existing 341 | file mkdir $DestDir 342 | 343 | # Extract from all provided files the NaturalDocs documentation and generate 344 | # the corresponding MarkDown file. 345 | foreach NdFile $NdFileList { 346 | if {$OutFile!=""} { 347 | set MdFile $OutFile 348 | } else { 349 | regsub {\.\w*$} [file tail $NdFile] {.md} MdFile 350 | if {[regexp {/modules/} $NdFile]} {set MdFile "Module-$MdFile"} 351 | if {[regexp {/targets/} $NdFile]} {set MdFile "Target-$MdFile"} 352 | catch {set MdFile $nd2md_nd2md($NdFile)} 353 | set MdFile $DestDir/$MdFile 354 | } 355 | 356 | set LinkFile [file tail $MdFile] 357 | regsub {\.md$} $LinkFile {} LinkFile 358 | 359 | set FileFormat $Format 360 | if {$FileFormat==""} { 361 | regexp {\.(\w*)$} [file tail $NdFile] {} FileFormat 362 | } 363 | set FileFormat [string tolower $FileFormat] 364 | 365 | #if {[file exists $MdFile] && [file mtime $NdFile]<[file mtime $MdFile]} continue 366 | 367 | nd2md $NdFile $MdFile $LinkFile $FileFormat 368 | } 369 | 370 | if {[llength $NdFileList]} StoreIndex 371 | 372 | if {$GenIndex} { 373 | GenIndexFile $DestDir/$nd2md_config(index_file) } 374 | 375 | exit -------------------------------------------------------------------------------- /developper/doc/thc_Web.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Drolla/thc/e94180857c0d43f48d0e93b2b46798d7f5e4a7be/developper/doc/thc_Web.gif -------------------------------------------------------------------------------- /developper/doc/thc_doc_style.css: -------------------------------------------------------------------------------- 1 | p { 2 | text-indent: 0; 3 | margin-bottom: 1em; 4 | } 5 | 6 | .CDLEntry { /* Override the default NaturalyDoc style */ 7 | font: 10pt Verdana, Arial, sans-serif; 8 | /* color: #000000; */ 9 | white-space: wrap 10 | padding-bottom: .25em; 11 | } 12 | 13 | .CDescriptionList { 14 | margin: .5em 5ex .7ex 5ex } -------------------------------------------------------------------------------- /libs/pkgIndex.tcl: -------------------------------------------------------------------------------- 1 | # Source the pkgIndex files of all sub directories 2 | 3 | foreach dir [glob -type d [file dirname [info script]]/*] { 4 | if {[info exists [file join $dir pkgIndex.tcl]]} { 5 | source [file join $dir pkgIndex.tcl] } 6 | } 7 | -------------------------------------------------------------------------------- /libs/t2ws/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Andreas Drollinger 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 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, 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 THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /libs/t2ws/README.md: -------------------------------------------------------------------------------- 1 | # T2WS - Introduction 2 | 3 | **T2WS**, the **Tiny Tcl Web Server**, is a small HTTP server that is easily deployable and embeddable in Tcl applications. 4 | 5 | T2WS has the following features : 6 | 7 | - **Easy to use** : A few lines are sufficient to build a file server to to provide an application API (see example below) 8 | - **Fast** : About 90 responses per second on a Raspberry PI version 1 9 | - **Multi-port support** : Can handle multiple sites or ports 10 | - **SSL/TLS support** : Secure connections are supported via the TLS package 11 | - **Expandable** : A plugin interface allows expanding the T2WS feature set 12 | - **Template engine** : A template engine is available via a plugin 13 | - **Basic authentication** : Basic authentication is available via a plugin 14 | 15 | To add a T2WS web server to a Tcl application, load the T2WS package, create an application specific web server responder command and start the HTTP server for the desired port (e.g. 8085) : 16 | 17 | ``` 18 | package require t2ws 19 | 20 | proc MyResponder {Request} { 21 | # Process the request URI: Extract a command and its arguments 22 | regexp {^/(\w*)/(.*)$} [dict get $Request URI] {} Command Arguments 23 | 24 | # Implement the different commands (eval , file ) 25 | switch -exact -- $Command { 26 | "eval" { 27 | set Data [uplevel #0 $Arguments] 28 | return [dict create Body $Data Content-Type "text/plain"] } 29 | "file" { 30 | return [dict create File $Arguments] } 31 | } 32 | 33 | # Return the status 404 (not found) if the command is unknown 34 | return [dict create Status "404"] 35 | } 36 | 37 | t2ws::Start 8085 -responder ::MyResponder 38 | ``` 39 | 40 | With this responder command example the web server will accept the commands _eval_ and _file_ and return an error for other requests : 41 | 42 | ``` 43 | http://localhost:8085/eval/glob *.tcl 44 | -> pkgIndex.tcl t2ws.tcl t2ws_template.tcl 45 | http://localhost:8085/file/pkgIndex.tcl 46 | -> if {![package vsatisfies [package provide Tcl] 8.5]} {return} ... 47 | http://localhost:8085/exec/cmd.exe 48 | -> 404 Not Found 49 | ``` 50 | 51 | Multiple responder commands can be defined for different purposes. The following example is equivalent to the previous one, but it uses separate responder commands for the command evaluation and for the file access : 52 | 53 | ``` 54 | package require t2ws 55 | 56 | proc MyResponder_Eval {Request} { 57 | set Data [uplevel #0 [dict get $Request URITail]] 58 | return [dict create Body $Data Content-Type "text/plain"] 59 | } 60 | 61 | proc MyResponder_File {Request} { 62 | return [dict create File [dict get $Request URITail]] 63 | } 64 | 65 | set Port [t2ws::Start 8085] 66 | t2ws::DefineRoute $Port ::MyResponder_Eval -method GET -uri "/eval/*" 67 | t2ws::DefineRoute $Port ::MyResponder_File -method GET -uri "/file/*" 68 | ``` 69 | 70 | ### What's next 71 | 72 | Start exploring the documentation resources for T2WS : 73 | 74 | * [T2WS - Main module](https://github.com/Drolla/t2ws/wiki/t2ws) provides all information about the T2WS web server main module. 75 | * [T2WS - Template](https://github.com/Drolla/t2ws/wiki/t2ws_template) provides information about the T2WS web server template engine plugin. 76 | * [T2WS - BAuth](https://github.com/Drolla/t2ws/wiki/t2ws_bauth) provides information about the basic authentication plugin. 77 | * [T2WS - Index](https://github.com/Drolla/t2ws/wiki/Index) index register. 78 | 79 | -------------------------------------------------------------------------------- /libs/t2ws/pkgIndex.tcl: -------------------------------------------------------------------------------- 1 | if {![package vsatisfies [package provide Tcl] 8.5]} {return} 2 | package ifneeded t2ws 0.6 [list source [file join $dir t2ws.tcl]] 3 | package ifneeded t2ws::template 0.4 [list source [file join $dir t2ws_template.tcl]] 4 | package ifneeded t2ws::bauth 0.2 [list source [file join $dir t2ws_bauth.tcl]] 5 | -------------------------------------------------------------------------------- /libs/t2ws/t2ws_bauth.tcl: -------------------------------------------------------------------------------- 1 | ########################################################################## 2 | # T2WS - Tiny Tcl Web Server 3 | ########################################################################## 4 | # t2ws_bauth.tcl - Basic authentication plugin for T2WS 5 | # 6 | # This file provides a basic authentication plugin the T2WS web server 7 | # 8 | # Copyright (C) 2016 Andreas Drollinger 9 | ########################################################################## 10 | # See the file "LICENSE" for information on usage and redistribution 11 | # of this file, and for a DISCLAIMER OF ALL WARRANTIES. 12 | ########################################################################## 13 | 14 | # Title: T2WS BAuth - Basic Authentication support for T2WS 15 | # 16 | # Group: Introduction 17 | # 18 | # This plugin provides basic HTTP authentication to the T2WS server. It is 19 | # loaded and enabled by executing the following commands : 20 | # 21 | # > package require t2ws::bauth 22 | # > t2ws::EnablePlugin $Port t2ws::bauth 23 | # 24 | # After loading this package the available login credentials have to be defined 25 | # by defining the dictionary variable 't2ws::bauth::LoginCredentials' : 26 | # 27 | # > set t2ws::bauth::LoginCredentials [dict create \ 28 | # > \ 29 | # > \ 30 | # > ... \ 31 | # > ] 32 | # 33 | # Once this setup is completed the T2WS web server requires a basic 34 | # authentication from the HTTP clients. For HTTP requests that use known login 35 | # credentials the plugin adds to the request dictionary the element 'User' 36 | # that contains the recognized user name and that can be read by the responder 37 | # commands. 38 | # 39 | # 40 | # Group: Security considerations 41 | # 42 | # The basic HTTP authentication doesn't provide any encryption. Using HTTP 43 | # the login credentials can easily be decoded. A secure connection can only 44 | # be guaranteed if basic authentication is used in combination with a secure 45 | # SHTTP connection (using the SSL/TLS extension). 46 | 47 | 48 | # Package requirements, configurations and variables 49 | 50 | package require Tcl 8.5 51 | package require t2ws 52 | package require base64 53 | 54 | namespace eval t2ws::bauth {} 55 | 56 | 57 | # Group: Configuration 58 | 59 | # Specification of the configuration options of the package, their default 60 | # values and the validity check. 61 | 62 | namespace eval t2ws::bauth { 63 | variable ConfigDefinitions [dict create \ 64 | -realm {"T2WS Web Server" 1} \ 65 | ] 66 | } 67 | 68 | ########################## 69 | # Proc: t2ws::bauth::Configure 70 | # Set and get T2WS Basic Authentication plugin configuration options. 71 | # This command can be called in 3 different ways : 72 | # 73 | # t2ws::bauth::Configure - Returns the currently defined T2WS configuration 74 | # t2ws::bauth::Configure