diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9efd13a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,25 @@ +FROM node:10-jessie +MAINTAINER Wolfgang Hottgenroth + +ARG APP_DIR="/opt/app" + +EXPOSE 4200 + +RUN mkdir -p $APP_DIR + +WORKDIR $APP_DIR + +COPY files files/ +COPY docroot docroot/ +COPY src src/ +COPY homepage.conf package.json package-lock.json tsconfig.json ./ + + + +RUN \ + npm install && \ + node_modules/typescript/bin/tsc -p ./ + + +CMD [ "node", "dist/main.js" ] + diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..ae972f4 --- /dev/null +++ b/build.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +docker build --tag wollud1969/homepage:latest --tag wollud1969/homepage:1.0 . + + diff --git a/legacy/posts/2016-10-14.01/article.html b/legacy/posts/2016-10-14.01/article.html deleted file mode 100644 index add04de..0000000 --- a/legacy/posts/2016-10-14.01/article.html +++ /dev/null @@ -1,38 +0,0 @@ -define(`TITLE', `Three Phase Inverter') -define(`DATE', `2016-10-14') -define(`CONTENT', ` -Already when I was still in school, about 30 years ago, I was curious to make an inverter using some MOSFETs. I actually was able to build a simple one phase inverter with rectangular signal shape (I used a NE555). Using this thing I drove a transformer to light a blub. However, all of these inverters I built passed by in fire. - -Now, I tried it again, not longer using MOSFETs but IGBTs with free-wheeling diode. Moreover, I used some microcontrollers and sine values to feed a PWM to get a sine-alike signal shape. And immediately with three phases to drive an asynchronous motor. - -img_0053 - -The signal shaping is done with four MSP430 controllers, three as PWMs to drive the bridge and one to coordinate and control the three PWMs. The PWM controller is decoupled from the IGBT driver (IR2184) using optic couplers. - -img_0054 - -The bridge is a three phase IGBT module is a 6MB120F-060 I got for a few euros at ebay. - -img_0055 - -To avoid high voltages in my setup I got a 24V async motor, also from ebay. - -img_0056 - -The PWMs generate the signal from a sine table generated using Excel. Those we got this signal: -inverter0_2016-09-23-4 - -The main task of the coordinator is the start the PWMs with a phase shift of 120° (digital line 1, 2 and 3): -2016-10-13_1 - -Currently the PWMs start with random polarity. The interesting signals are the digital lines 4, 5 and 6. - -Sometimes the motor runs: -2016-10-13_works - -But sometimes not: -2016-10-13_works_not - -The firmware is available on bitbucket, for the PWM controllers here and for the coordinator here. - -') \ No newline at end of file diff --git a/legacy/posts/2016-11-02.01/article.html b/legacy/posts/2016-11-02.01/article.html deleted file mode 100644 index 857a87d..0000000 --- a/legacy/posts/2016-11-02.01/article.html +++ /dev/null @@ -1,47 +0,0 @@ -define(`TITLE', `Something really useful: 433MHz Power-Outlet Control') -define(`DATE', `2016-11-02') -define(`CONTENT', ` -We've lots of more or less cheap 433MHz Switchable Power-Outlets in the house, mostly for decorative lights. You get them for under 15€ in the Building Center, three at once with a remote control. Usually, you can control four switches with one remote, period. (A promising exceptions are the device from Intertechno.) - -Now I was looking for a way to -
    -
  1. Control the switches from different manufacturers with one remote.
  2. -
  3. Control them from really remote - from the office or from holiday.
  4. -
  5. Control them programmatically.
  6. -
-There are a couple of Arduino libraries out there which are working with this cheap 433MHz senders and receivers from China: - -  - -sender_receiverI tried several ones, not all a really working, but finally I stopped at https://github.com/sui77/rc-switch, which works really good. - - - - -First challenge now is to get the codes out of the remotes. For this purposes the rc-switch library provides an example sketch for the Arduino. I extended it a bit and got this: - -img_0101 -  -img_0105 -  - -Software for this thing can be found here https://gitlab.com/wolutator/433Receiver.git. - -This is how it works: - -img_0111 -  - -The second challenge is to send the codes out into air and let the power switches receive them. This is done with this thing: - -img_0100 - -It is a Arduino Ethernet Board with a PoE-adapter and the 433MHz sender directly attached to it. I glued it under a table in the living room. - -This thing received messages via MQTT and send them out via 433MHz. - -The software is here https://gitlab.com/wolutator/Mqtt433Gateway.git - -BTW: do not expect beautiful software, this has been made on Halloween evening and night when waiting for the kids to come home. - -') \ No newline at end of file diff --git a/legacy/posts/2016-12-19.01/article.html b/legacy/posts/2016-12-19.01/article.html deleted file mode 100644 index a5b0edd..0000000 --- a/legacy/posts/2016-12-19.01/article.html +++ /dev/null @@ -1,26 +0,0 @@ -define(`TITLE', `Three Phase Inverter, Second Service') -define(`DATE', `2016-12-19') -define(`CONTENT', ` -I wrote in October about my first try to build a simple three phase inverter, see here https://a385e5.wordpress.com/2016/10/14/three-phase-inverter/. In the first try I used four MSP430 microcontroller, one for the PWM of each phase and one to coordinate the phase shift of the three phases. - -In this experiment I put everything on one STM32 microcontroller. Here I used the DMA feature to feed data into the PWM counter and I calculated the sine values at start-up time on the microcontroller. Additionally I put in the driver for a CAN interface, however, it is not yet supported in the firmware. - -img_0140 - -From top to bottom you see the CAN driver, the STM32 board, opto coupler to separate logic and power part and then from right to left in the bottom half the low-side/high-side MOSFET drivers and the MOSFETs. - -img_0144 - -The power supply consists of a traditional transformer and (top right) the rectifier and condensers for the power part, together with the 12V regulator for the drivers and (top left) the regulators for 3.3V and 5V for the logic part. - -img_0146 - -The motor is the same as in the earlier experiment - I don't have too much of them. And everything is put onto one board: - -  - -  -img_0143 - -(Some space reserved for a HMI unit to be connected via CAN ...) -') \ No newline at end of file diff --git a/legacy/posts/2018-01-26.01/article.html b/legacy/posts/2018-01-26.01/article.html deleted file mode 100644 index 46cde0e..0000000 --- a/legacy/posts/2018-01-26.01/article.html +++ /dev/null @@ -1,277 +0,0 @@ -define(`TITLE', `Configuration-Webserver for ESP8266 Projects') -define(`DATE', `2018-01-26') -define(`CONTENT', ` -In my previous ESP8266 based weekend projects I always hardcoded configuration data. For the ESP8266 these are at least the WiFi credentials SSID and WPA key. Moving it into a different WiFi network requires re-flashing it. There must be a better way I thought and found that's a single line of code to run the ESP8266 as an accesspoint, which opens its own WiFi network. - -So, I first hardcoded a web page with a form to enter configuration data, a data structure to hold it and some code to store it into the EEPROM or load it there. -It appears that this was an error-prone process with a lot of redudancy in the code. - -For that reason I wrote an approach with a small template-based generator script: - - - - -[code language="python" title="configGen.py"] -#!/usr/bin/python - -from Cheetah.Template import Template - -configItems = [ - {"label":"_", "key":"magic", "type":"I", "default": ""}, - {"label":"Wifi SSID", "key":"wifiSsid", "type":"C", "length":32, "default":"test"}, - {"label":"Wifi Key", "key":"wifiKey", "type":"C", "length":64, "default":"geheim"}, - {"label":"MQTT Broker", "key":"mqttBroker", "type":"C", "length":64, "default":"broker.hottis.de"}, - {"label":"MQTT Username", "key":"mqttUser", "type":"C", "length":32, "default":"esp1"}, - {"label":"MQTT Password", "key":"mqttPass", "type":"C", "length":32, "default":"geheim"}, - {"label":"MQTT ClientId", "key":"mqttClientId", "type":"C", "length":32, "default":"changeThis"}, - {"label":"MQTT Topic", "key":"mqttTopic", "type":"C", "length":64, "default":"IoT/espThermometer2/location/measurement"}, - {"label":"MQTT Port", "key":"mqttPort", "type":"I", "default":8883}, - {"label":"Measure Period", "key":"measurePeriod", "type":"I", "default":300} -] - -h_file = Template(file="configuration_h.tmpl", searchList=[{"configItems":configItems}]) -open('configuration.h','w').write(str(h_file)) -c_file = Template(file="configuration_c.tmpl", searchList=[{"configItems":configItems}]) -open('configuration.cpp','w').write(str(c_file)) -[/code] - - -The two templates are: - -[code language="C" title="configuration_h.tmpl"] -typedef struct { -#for $configItem in $configItems -#if $configItem.type == 'C' - char ${configItem.key}[$configItem.length]; -#else if $configItem.type == 'I' - uint32_t $configItem.key; -#end if -#end for -} tConfigBlock; - -extern const uint32_t MAGIC; -extern tConfigBlock configBlock; - -void configServeIndex(); -void configServeGetConfiguration(); -void showConfiguration(); -[/code] - -And: - -[code language="C" title="configuration_c.tmpl"] -#raw -#include <Arduino.h> - -#include <ESP8266WiFi.h> -#include <ESP8266WebServer.h> -#include <EEPROM.h> - -#include "defines.h" -#include "configuration.h" -#end raw - - -tConfigBlock configBlock; -const uint32_t MAGIC = 0xC0DE0001; -extern ESP8266WebServer webServer; - -bool configSaved = false; - -void configServeIndex() { - bool configValid = (configBlock.magic == MAGIC); - - if (! configValid) { - #for $configItem in $configItems - #if $configItem.label != "_" - #if $configItem.type == "C" - strcpy(configBlock.$configItem.key, "$configItem.default"); - #else if $configItem.type == "I" - configBlock.$configItem.key = $configItem.default; - #end if - #end if - #end for - } - - String buffer = - "<!doctype html" - "<html lang=\"en\">" - " <head>" - " <title>ESP8266 Thermometer Configuration Page</title>" - " </head>" - " <body>" - " <h1>ESP8266 Configuration Page</h1>"; - - if (configSaved) { - configSaved = false; - buffer += "<h2>Configuration saved</h2>"; - } - - buffer += - " <form action=\"/config\" method=\"GET\">" - " <table>" - #for $configItem in $configItems - #if $configItem.label != "_" - " <tr>" - " <td>" - " <label for\"$configItem.key\">$configItem.label</label>" - " </td><td>" - " <input type=\"text\" name=\"$configItem.key\" id=\"$configItem.key\" "; - - #if $configItem.type == "C" - buffer += " size=\"$configItem.length\" "; - buffer += " value=\""; - buffer += configBlock.$configItem.key; - buffer += "\""; - #else if $configItem.type == "I" - buffer += " value=\""; - buffer += configBlock.$configItem.key; - buffer += "\""; - #end if - - buffer += - " />" - " </td>" - " </tr>" - #end if - #end for - " <tr>" - " <td colspan=\"2\">" - " <button type=\"submit\">Save</button>" - " </td>" - " </tr>" - " </table>" - " </form>" - " </body>" - "</html>"; - - webServer.send(200, "text/html", buffer); - - -#ifdef DEBUG - Serial.println("indexHtml request served"); -#endif -} - -void configServeGetConfiguration() { - String arg; - - #for $configItem in $configItems - #if $configItem.label != "_" - arg = webServer.arg("$configItem.key"); - #if $configItem.type == "C" - strcpy(configBlock.$configItem.key, arg.c_str()); - #else if $configItem.type == "I" - configBlock.$configItem.key = atoi(arg.c_str()); - #end if - #end if - #end for - - configBlock.magic = MAGIC; - - showConfiguration(); - - EEPROM.begin(512); - EEPROM.put(EEPROM_ADDR, configBlock); - EEPROM.commit(); - - Serial.println("EEPROM saved"); - - configSaved = true; - webServer.sendHeader("Location", String("/"), true); - webServer.send(302, "text/plain", ""); - //webServer.send(200, "text/html", "configuration saved"); -} - -void showConfiguration() { - Serial.println("Configuration is"); - - #for $configItem in $configItems - Serial.print("$configItem.key = "); - Serial.println(configBlock.$configItem.key); - - #end for - - Serial.println("---"); -} -[/code] - -Besides these generated files I also needed a framework to distinguish between "configuration mode" and "production mode" and in configuration mode to start the WiFi accesspoint. - -Since I'm programming the ESP8266 in an Eclipse-based Arduino-environment, this is all done in the setup() and loop() function: - -[code language="C"] -void setup() { - startTime = millis(); -#ifdef DEBUG - Serial.begin(115200); - Serial.println("Starting ..."); -#endif - - pinMode(CONFIG_SWITCH, INPUT_PULLUP); - pinMode(LED_PIN, OUTPUT); - - EEPROM.begin(512); - EEPROM.get(EEPROM_ADDR, configBlock); - - Serial.print("Magic: "); - Serial.println(configBlock.magic); - - configMode = ((LOW == digitalRead(CONFIG_SWITCH)) || (configBlock.magic != MAGIC)); - - if (configMode) { -#ifdef DEBUG - Serial.println("Configuration mode"); -#endif - digitalWrite(LED_PIN, LOW); - setupConfiguration(); - } else { -#ifdef DEBUG - Serial.println("Production mode"); - Serial.println(); - Serial.println(); - showConfiguration(); -#endif - - digitalWrite(LED_PIN, HIGH); - setupProduction(); - } - -#ifdef DEBUG - Serial.println("Started."); -#endif -} - -void loop() { - if (configMode) { - loopConfiguration(); - } else { - loopProduction(); - } -} - -void setupConfiguration() { - WiFi.mode(WIFI_AP); - WiFi.softAP(CONFIG_SSID); -#ifdef DEBUG - Serial.println("AP started"); -#endif - - webServer.on("/", configServeIndex); - webServer.on("/config", configServeGetConfiguration); - webServer.onNotFound(configServeNotFound); - webServer.begin(); -#ifdef DEBUG - Serial.println("Webserver started"); -#endif -} - -void loopConfiguration() { - webServer.handleClient(); -} -[/code] - - -This code can be also found embedded into two of my projects. Find them at https://gitlab.com/wolutator/EspThermometer2 and https://gitlab.com/wolutator/TouchSwitch. - -') \ No newline at end of file diff --git a/legacy/posts/2018-02-22.01/article.html b/legacy/posts/2018-02-22.01/article.html deleted file mode 100644 index 750514d..0000000 --- a/legacy/posts/2018-02-22.01/article.html +++ /dev/null @@ -1,29 +0,0 @@ -define(`TITLE', `Home Automation Hub') -define(`DATE', `2018-02-22') -define(`CONTENT', ` -My home automation hub. (Photos inside) - -IMG_0304 - -IMG_0195 - -A Raspberry Pi runs Homegear and homekit2mqtt. It is equipped with two 866MHz radios for Homematic and MAX!. - -Additionally an MQTT broker and the homegrown control software (https://gitlab.com/wolutator/dispatcher_ng), which communicates with Homegear, homekit2mqtt, the MQTT433MHz bridge (see below) and other homegrown web clients via MQTT, resists on it. - -IMG_0307 - -There is also a DIY MQTT to 433MHz bridge to control Intertechno and other 433MHz plugs (https://gitlab.com/wolutator/Mqtt433Gateway). - -  - -  - -  - -  - -IMG_0308 - -An finally a Philips Hue Bridge powered using a PoE adaptor for Philips and IKEA Tradfri bulbs, paired to Homegear. -') \ No newline at end of file diff --git a/legacy/posts/2018-04-30.01/article.html b/legacy/posts/2018-04-30.01/article.html deleted file mode 100644 index 7470c83..0000000 --- a/legacy/posts/2018-04-30.01/article.html +++ /dev/null @@ -1,143 +0,0 @@ -define(`TITLE', `Yet Another Debouncing Method') -define(`DATE', `2018-04-30') -define(`CONTENT', ` -You can find several approaches for debouncing mechanical switches on the Internet, some work better, some not so good. - -One common approach is to ignore events in an ISR when they come too fast: - -[code language="C"] -void count() { - static uint32_t lastEvent = 0; - uint32_t currentEvent = micros(); - if (currentEvent > (lastEvent + configBlock.debounce)) { - lastEvent = currentEvent; - cnt++; - } -} - -void setup() { - pinMode(REED_PIN, INPUT_PULLUP); - attachInterrupt(REED_PIN, count, FALLING); -} -[/code] - -This works very good when only the tipping of a switch is relevant. - -When also the time the button was pressed is relevant and when it is especially necessary to distinguish between a short and a long press this approach doesn't work anymore. - -Since I couldn't remember the approaches I read about earlier I've sketched this state machine: - - - - - - -20180430110848869_0001.jpg - -(The double-lined states are action-states which send out the related information.) - -At least for me, this approach is working very reliable so far, I'm quite happy with it. - -[code language="C"] -enum tPressedState { psHIGH, psLOW, psACCEPTED_LOW, psLONG_START, psLONG_CONT, psLONG_CONT_SEND, psLONG_END, psSHORT, psINVALID }; - -typedef struct { - uint8_t index; - uint8_t buttonPin; - tPressedState pressedState; - tPressedState oldPressedState; - uint32_t lastStateChange; -} tButton; - -tButton buttons[] = { - { 1, SWITCH_1, psHIGH, psINVALID, 0 }, - { 2, SWITCH_2, psHIGH, psINVALID, 0 }, - { 3, SWITCH_3, psHIGH, psINVALID, 0 }, - { 0, 0, psINVALID, psINVALID, 0 } // END MARKER -}; - -static void buttonHandler(tButton *button) { - uint32_t currentMicros = micros(); - uint8_t buttonState = digitalRead(button->buttonPin); - -#ifdef DEBUG - if (button->oldPressedState != button->pressedState) { - Serial.print("Index "); - Serial.print(button->index); - Serial.print(", state changed from "); - Serial.print(button->oldPressedState); - Serial.print(" to "); - Serial.print(button->pressedState); - Serial.println(); - button->oldPressedState = button->pressedState; - } -#endif - - switch (button->pressedState) { - case psHIGH: - if (buttonState == LOW) { - button->pressedState = psLOW; - button->lastStateChange = currentMicros; - } - break; - case psLOW: - if (buttonState == HIGH) { - button->pressedState = psHIGH; - button->lastStateChange = currentMicros; - } else { - if (currentMicros > (button->lastStateChange + configBlock.debounce)) { - button->pressedState = psACCEPTED_LOW; - button->lastStateChange = currentMicros; - } - } - break; - case psACCEPTED_LOW: - if (buttonState == HIGH) { - button->pressedState = psSHORT; - button->lastStateChange = currentMicros; - } - if (currentMicros > (button->lastStateChange + (configBlock.longPress * 1000))) { - button->pressedState = psLONG_START; - button->lastStateChange = currentMicros; - } - break; - case psSHORT: - sendMsg(button->index, "PRESS_SHORT"); - button->pressedState = psHIGH; - button->lastStateChange = currentMicros; - break; - case psLONG_START: - sendMsg(button->index, "PRESS_LONG_START"); - button->pressedState = psLONG_CONT; - button->lastStateChange = currentMicros; - break; - case psLONG_CONT: - if (buttonState == HIGH) { - button->pressedState = psLONG_END; - button->lastStateChange = currentMicros; - } - if (currentMicros > (button->lastStateChange + (configBlock.longPressRepeat * 1000))) { - button->pressedState = psLONG_CONT_SEND; - button->lastStateChange = currentMicros; - } - break; - case psLONG_CONT_SEND: - sendMsg(button->index, "PRESS_LONG_CONT"); - button->pressedState = psLONG_CONT; - button->lastStateChange = currentMicros; - break; - case psLONG_END: - sendMsg(button->index, "PRESS_LONG_END"); - button->pressedState = psHIGH; - button->lastStateChange = currentMicros; - break; - default: - button->pressedState = psHIGH; - button->lastStateChange = currentMicros; - } -} -[/code] - -Find it embedded in the code of a small ESP8266-based switch thing I'm using in my home automation setup (home grown control code (https://gitlab.com/wolutator/dispatcher_ng), homegear (https://homegear.eu/) for device integration and openHAB (https://www.openhab.org/) as user interface) here: https://gitlab.com/wolutator/MySwitch. - -') \ No newline at end of file diff --git a/src/config.ts b/src/config.ts index f406ea4..656ba73 100644 --- a/src/config.ts +++ b/src/config.ts @@ -5,7 +5,7 @@ import * as cmdargs from 'command-line-args' const OPTION_DEFINITIONS = [ { name: 'verbose', alias: 'v', type: Boolean }, - { name: 'config', alias: 'c', type: String, defaultValue: '~/homepage.conf' } + { name: 'config', alias: 'c', type: String, defaultValue: './homepage.conf' } ];