61 Commits

Author SHA1 Message Date
125d89d632 fix ci script 2022-11-15 09:37:50 +01:00
670fb8f97b add mastodon link 2022-11-15 09:32:57 +01:00
3aed319835 image changed 2021-05-15 14:07:58 +02:00
fce5ff4743 add image 2021-05-15 14:04:31 +02:00
7742892afe article on mainscnt 2021-05-15 13:55:28 +02:00
74543f3b5f new version 2020-10-19 17:23:32 +02:00
3a22172081 fix run command 2020-10-19 17:19:10 +02:00
5c31d78885 try environments 2020-10-19 16:57:06 +02:00
975ffa4bfb changed gpg key 2020-06-24 20:07:13 +02:00
82de380596 fix url 2020-06-24 19:55:03 +02:00
4e567c86ec new article 2020-06-24 19:53:17 +02:00
5bf51b58bb fix ci script 2020-06-24 19:46:02 +02:00
bfffd3b235 update CI 2020-06-24 19:44:49 +02:00
a44eab1591 drop postal address 2020-02-09 17:50:40 +01:00
48cb3e6972 some mistakes fixes 2020-02-09 17:43:02 +01:00
9a46c44d94 new post 2020-02-09 17:35:27 +01:00
24467c80ec fix code 2019-07-17 18:18:52 +02:00
98fc271eb7 ssh and screen 2019-07-17 18:15:26 +02:00
912c8e4d04 trigger ci script 2019-02-16 22:57:40 +01:00
3e6d42fed4 bump version 2019-02-16 18:51:17 +01:00
ca9d6c19d4 change to see the restart 2019-02-16 18:50:57 +01:00
5f9136b74b another fix in ci script 2019-02-16 18:46:28 +01:00
bf5664b2af another fix in ci script 2019-02-16 18:43:08 +01:00
7e1127efcf fix ci script 2019-02-16 18:39:09 +01:00
b20acc86c2 a change to test deploy target 2019-02-16 18:36:51 +01:00
f20bfe2b30 fix ci script again 2019-02-16 18:28:16 +01:00
1911c34faa new test 2019-02-16 18:21:13 +01:00
cf9c04e211 fix ci script 2019-02-16 18:09:52 +01:00
953f92711c add build docker image in ci script 2019-02-16 18:06:45 +01:00
c03e25d647 use only spaces instead of tabs 2019-02-15 20:06:38 +01:00
0b7b8392ed add ci script 2019-02-15 20:04:31 +01:00
298e02349a increase docker tag 2019-01-04 09:19:08 +01:00
1f68c5a8ea tweetbot explained 2019-01-04 09:11:01 +01:00
fccaeed07e more articles 2019-01-03 20:59:50 +01:00
77cff49e41 Merge branch 'master' of gitlab.com:wolutator/homepage 2019-01-03 19:23:36 +01:00
3c52ec4691 dockerized 2019-01-03 19:22:49 +01:00
d43b935d13 merged 2018-06-28 17:01:55 +02:00
525b6313c2 Merge branch 'master' into branchOne 2018-06-28 16:02:21 +02:00
46057cac31 major changes in branchTwo 2018-06-28 16:01:22 +02:00
29208faaec move .gitignore in master branch too 2018-06-28 15:54:48 +02:00
9a817b27c1 .gitignore was in the wrong place 2018-06-28 15:52:06 +02:00
ee2eca37dc minor changes in branchOne 2018-06-28 15:51:19 +02:00
990ac05bba Merge branch 'master' into test1 2018-06-28 14:49:49 +02:00
69b2c58240 another post converted 2018-06-28 14:21:08 +02:00
f71211fe55 ignore editor backups and minor change 2018-06-28 12:04:01 +02:00
194dc8da13 photo of homegear 2018-06-05 11:03:30 +02:00
0a031e562d Merge branch 'master' of gitlab.com:wolutator/homepage 2018-06-05 10:59:42 +02:00
cd3cce51ff hm config print 2018-06-05 10:59:30 +02:00
cedc1a96ef Merge branch 'master' of https://gitlab.com/wolutator/homepage 2018-05-28 11:16:38 +02:00
3d2d441fed photo added 2018-05-28 11:16:14 +02:00
4f9352c2ee fix image name 2018-05-25 13:48:08 +02:00
27d3fd02a5 some more articles converted 2018-05-25 13:44:55 +02:00
bc516fa417 remove debug code 2018-05-25 13:05:35 +02:00
82a4bfab86 extend impressum 2018-05-25 13:04:32 +02:00
8c5574c054 resize some photos 2018-05-24 14:45:43 +02:00
afbedcf7d3 base debug 2018-05-24 14:28:07 +02:00
9821d412ec another post converted 2018-05-24 02:03:20 +02:00
984174a44e change font and background color 2018-05-24 01:32:30 +02:00
c574383eec another post converted 2018-05-24 01:20:18 +02:00
85d5d2c2fc remove some obsolete debug code 2018-05-24 01:05:14 +02:00
35e30abd69 some improvements 2018-05-24 01:02:39 +02:00
86 changed files with 1347 additions and 877 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*~

41
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,41 @@
image: docker:stable
stages:
- build
- deploy
variables:
IMAGE_NAME: registry.hottis.de/wolutator/homepage
build:
stage: build
tags:
- hottis
- linux
- docker
script:
- VERSION=`cat VERSION`
- echo "Version is $VERSION"
- docker build --tag ${IMAGE_NAME}:latest --tag ${IMAGE_NAME}:$VERSION .
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
- docker push ${IMAGE_NAME}:latest
- docker push ${IMAGE_NAME}:$VERSION
deploy:
stage: deploy
tags:
- hottis
- linux
- docker
script:
- VERSION=`cat VERSION`
- echo "Version is $VERSION"
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
- docker stop homepage || echo "homepage not running, anyway okay"
- docker rm homepage || echo "homepage not available, anyway okay"
- docker pull ${IMAGE_NAME}:$VERSION
- docker run -d --restart=always --name homepage --network ${PROD_NETWORK} --ip ${PROD_ADDRESS} ${IMAGE_NAME}:$VERSION
environment:
name: production
url: https://home.hottis.de/wolutator/

25
Dockerfile Normal file
View File

@ -0,0 +1,25 @@
FROM node:10-jessie
MAINTAINER Wolfgang Hottgenroth <wolfgang.hottgenroth@icloud.com>
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 ./
COPY VERSION .
RUN \
npm install && \
node_modules/typescript/bin/tsc -p ./
CMD [ "node", "dist/main.js" ]

1
VERSION Normal file
View File

@ -0,0 +1 @@
1.1.1

2
dist/config.js vendored
View File

@ -4,7 +4,7 @@ const fs = require("fs");
const cmdargs = require("command-line-args"); const cmdargs = require("command-line-args");
const OPTION_DEFINITIONS = [ const OPTION_DEFINITIONS = [
{ name: 'verbose', alias: 'v', type: Boolean }, { name: 'verbose', alias: 'v', type: Boolean },
{ name: 'config', alias: 'c', type: String, defaultValue: '~/homepage.conf' } { name: 'config', alias: 'c', type: String, defaultValue: './homepage.conf' }
]; ];
function readConfig() { function readConfig() {
let options = cmdargs(OPTION_DEFINITIONS); let options = cmdargs(OPTION_DEFINITIONS);

12
dist/main.js vendored
View File

@ -6,18 +6,14 @@ const logger = require("./log");
const express = require("express"); const express = require("express");
function getPageOptions(contentStr) { function getPageOptions(contentStr) {
let pageOptions = {}; let pageOptions = {};
// logger.info(`contentStr: ${contentStr}`)
try { try {
let lines = contentStr.split("\n"); let lines = contentStr.split("\n");
let firstLine = lines[0]; let firstLine = lines[0];
// logger.info(`firstLine: ${firstLine}`)
let pageOptionsStr = firstLine.replace(/^\s*<!-- (\{.+\}) -->[\s\S]*$/, "\$1"); let pageOptionsStr = firstLine.replace(/^\s*<!-- (\{.+\}) -->[\s\S]*$/, "\$1");
// logger.info(`pageOptionsStr: ${pageOptionsStr}`)
pageOptions = JSON.parse(pageOptionsStr); pageOptions = JSON.parse(pageOptionsStr);
// logger.info(JSON.stringify(pageOptions))
} }
catch (_a) { catch (_a) {
// logger.info("No pageOptions found") logger.info("No pageOptions found");
} }
return pageOptions; return pageOptions;
} }
@ -25,7 +21,7 @@ function getToc() {
logger.info("building toc"); logger.info("building toc");
let toc = ""; let toc = "";
let posts = fs.readdirSync('./docroot/posts'); let posts = fs.readdirSync('./docroot/posts');
posts.forEach((v) => { posts.sort().reverse().forEach((v) => {
let content = fs.readFileSync(`./docroot/posts/${v}/article.pag`); let content = fs.readFileSync(`./docroot/posts/${v}/article.pag`);
let contentStr = content.toString(); let contentStr = content.toString();
let pageOptions = getPageOptions(contentStr); let pageOptions = getPageOptions(contentStr);
@ -39,6 +35,7 @@ let masterTmpl;
let toc; let toc;
let cache = {}; let cache = {};
app.engine('pag', (filePath, options, callback) => { app.engine('pag', (filePath, options, callback) => {
// logger.info(JSON.stringify(options))
if (!(filePath in cache)) { if (!(filePath in cache)) {
logger.info(`${filePath} not yet in cache`); logger.info(`${filePath} not yet in cache`);
fs.readFile(filePath, (err, content) => { fs.readFile(filePath, (err, content) => {
@ -89,7 +86,8 @@ app.get('/reload', (req, res) => {
cache = {}; cache = {};
toc = getToc(); toc = getToc();
masterTmpl = fs.readFileSync('./docroot/master.tmpl').toString(); masterTmpl = fs.readFileSync('./docroot/master.tmpl').toString();
res.send('reload triggered'); let base = req.headers['x-proxy-original-url'] || "/";
res.redirect(`${base}index`);
}); });
app.use('/files', express.static('files')); app.use('/files', express.static('files'));
masterTmpl = fs.readFileSync('./docroot/master.tmpl').toString(); masterTmpl = fs.readFileSync('./docroot/master.tmpl').toString();

2
dist/main.js.map vendored
View File

@ -1 +1 @@
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;AAAA,yBAAwB;AAExB,mCAAkC;AAClC,gCAA+B;AAE/B,mCAAkC;AAGlC,wBAAwB,UAAkB;IACtC,IAAI,WAAW,GAAS,EAAE,CAAA;IAC1B,2CAA2C;IAC3C,IAAI;QACA,IAAI,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAClC,IAAI,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;QACxB,yCAAyC;QACzC,IAAI,cAAc,GAAG,SAAS,CAAC,OAAO,CAAC,+BAA+B,EAAE,KAAK,CAAC,CAAA;QAC9E,mDAAmD;QACnD,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAA;QACxC,2CAA2C;KAC9C;IAAC,WAAM;QACJ,sCAAsC;KACzC;IACD,OAAO,WAAW,CAAA;AACtB,CAAC;AAED;IACI,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;IAC3B,IAAI,GAAG,GAAY,EAAE,CAAA;IACrB,IAAI,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAA;IAC7C,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;QAChB,IAAI,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,mBAAmB,CAAC,cAAc,CAAC,CAAA;QACjE,IAAI,UAAU,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAA;QACnC,IAAI,WAAW,GAAG,cAAc,CAAC,UAAU,CAAC,CAAA;QAC5C,GAAG,IAAI,sBAAsB,CAAC,KAAK,CAAC,MAAM,WAAW,CAAC,KAAK,WAAW,CAAA;IAC1E,CAAC,CAAC,CAAA;IACF,OAAO,GAAG,CAAA;AACd,CAAC;AAKD,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAA;AAEhC,IAAI,GAAG,GAAG,OAAO,EAAE,CAAA;AAEnB,IAAI,UAAkB,CAAA;AACtB,IAAI,GAAW,CAAA;AACf,IAAI,KAAK,GAAQ,EAAE,CAAA;AAInB,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,QAAgB,EAAE,OAAY,EAAE,QAAa,EAAE,EAAE;IAChE,IAAI,CAAE,CAAC,QAAQ,IAAI,KAAK,CAAC,EAAE;QACvB,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,mBAAmB,CAAC,CAAA;QAE3C,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE;YACnC,IAAI,GAAG,EAAE;gBACL,OAAO,QAAQ,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAA;aAC1C;YAED,IAAI,UAAU,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAA;YACnC,IAAI,WAAW,GAAG,cAAc,CAAC,UAAU,CAAC,CAAA;YAC5C,IAAI,cAAc,GAAG,UAAU;iBAC9B,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;YAEzB,IAAI,cAAc,GAAG,UAAU;iBAC9B,OAAO,CAAC,gBAAgB,EAAE,cAAc,CAAC;iBACzC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;YAEjC,KAAK,IAAI,GAAG,IAAI,WAAW,EAAE;gBACzB,IAAI,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAA;gBAC5B,IAAI,GAAG,IAAI,KAAK,IAAI,KAAK,IAAI,SAAS,EAAE;oBACpC,KAAK,GAAG,GAAG,CAAA;iBACd;gBACD,cAAc,GAAG,cAAc,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,GAAG,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,CAAA;aAC9E;YAED,KAAK,CAAC,QAAQ,CAAC,GAAG,cAAc,CAAA;YAEhC,OAAO,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC,CAAA;QACzC,CAAC,CAAC,CAAA;KACL;SAAM;QACH,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,oBAAoB,CAAC,CAAA;QAC5C,OAAO,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAA;KACzC;AACL,CAAC,CAAC,CAAA;AAEF,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,WAAW,CAAC,CAAA;AAC7B,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,CAAC,CAAA;AAE7B,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IAC3B,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,sBAAsB,CAAC,IAAI,GAAG,EAAC,CAAC,CAAA;AAC9E,CAAC,CAAC,CAAA;AAEF,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IACjC,GAAG,CAAC,MAAM,CAAC,SAAS,GAAG,CAAC,MAAM,CAAC,IAAI,UAAU,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,sBAAsB,CAAC,IAAI,GAAG,EAAC,CAAC,CAAA;AACzG,CAAC,CAAC,CAAA;AAEF,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IACjC,GAAG,CAAC,MAAM,CAAC,SAAS,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,sBAAsB,CAAC,IAAI,GAAG,EAAC,CAAC,CAAA;AACjG,CAAC,CAAC,CAAA;AAEF,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IACtB,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAA;IACtC,IAAI,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,sBAAsB,CAAC,IAAI,GAAG,CAAA;IACrD,GAAG,CAAC,QAAQ,CAAC,GAAG,IAAI,OAAO,CAAC,CAAA;AAChC,CAAC,CAAC,CAAA;AAEF,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IAC5B,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;IAC/B,KAAK,GAAG,EAAE,CAAA;IACV,GAAG,GAAG,MAAM,EAAE,CAAA;IACd,UAAU,GAAG,EAAE,CAAC,YAAY,CAAC,uBAAuB,CAAC,CAAC,QAAQ,EAAE,CAAA;IAChE,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;AAChC,CAAC,CAAC,CAAA;AAEF,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAA;AAG1C,UAAU,GAAG,EAAE,CAAC,YAAY,CAAC,uBAAuB,CAAC,CAAC,QAAQ,EAAE,CAAA;AAChE,GAAG,GAAG,MAAM,EAAE,CAAA;AAEd,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE;IAClC,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAA;AACxC,CAAC,CAAC,CAAA;AACF,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA"} {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;AAAA,yBAAwB;AAExB,mCAAkC;AAClC,gCAA+B;AAE/B,mCAAkC;AAGlC,wBAAwB,UAAkB;IACtC,IAAI,WAAW,GAAS,EAAE,CAAA;IAC1B,IAAI;QACA,IAAI,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAClC,IAAI,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;QACxB,IAAI,cAAc,GAAG,SAAS,CAAC,OAAO,CAAC,+BAA+B,EAAE,KAAK,CAAC,CAAA;QAC9E,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAA;KAC3C;IAAC,WAAM;QACJ,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAA;KACtC;IACD,OAAO,WAAW,CAAA;AACtB,CAAC;AAED;IACI,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;IAC3B,IAAI,GAAG,GAAY,EAAE,CAAA;IACrB,IAAI,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAA;IAC7C,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;QACjC,IAAI,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,mBAAmB,CAAC,cAAc,CAAC,CAAA;QACjE,IAAI,UAAU,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAA;QACnC,IAAI,WAAW,GAAG,cAAc,CAAC,UAAU,CAAC,CAAA;QAC5C,GAAG,IAAI,sBAAsB,CAAC,KAAK,CAAC,MAAM,WAAW,CAAC,KAAK,WAAW,CAAA;IAC1E,CAAC,CAAC,CAAA;IACF,OAAO,GAAG,CAAA;AACd,CAAC;AAKD,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAA;AAEhC,IAAI,GAAG,GAAG,OAAO,EAAE,CAAA;AAEnB,IAAI,UAAkB,CAAA;AACtB,IAAI,GAAW,CAAA;AACf,IAAI,KAAK,GAAQ,EAAE,CAAA;AAInB,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,QAAgB,EAAE,OAAY,EAAE,QAAa,EAAE,EAAE;IAChE,uCAAuC;IACvC,IAAI,CAAE,CAAC,QAAQ,IAAI,KAAK,CAAC,EAAE;QACvB,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,mBAAmB,CAAC,CAAA;QAE3C,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE;YACnC,IAAI,GAAG,EAAE;gBACL,OAAO,QAAQ,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAA;aAC1C;YAED,IAAI,UAAU,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAA;YACnC,IAAI,WAAW,GAAG,cAAc,CAAC,UAAU,CAAC,CAAA;YAC5C,IAAI,cAAc,GAAG,UAAU;iBAC9B,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;YAEzB,IAAI,cAAc,GAAG,UAAU;iBAC9B,OAAO,CAAC,gBAAgB,EAAE,cAAc,CAAC;iBACzC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;YAEjC,KAAK,IAAI,GAAG,IAAI,WAAW,EAAE;gBACzB,IAAI,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAA;gBAC5B,IAAI,GAAG,IAAI,KAAK,IAAI,KAAK,IAAI,SAAS,EAAE;oBACpC,KAAK,GAAG,GAAG,CAAA;iBACd;gBACD,cAAc,GAAG,cAAc,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,GAAG,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,CAAA;aAC9E;YAED,KAAK,CAAC,QAAQ,CAAC,GAAG,cAAc,CAAA;YAEhC,OAAO,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC,CAAA;QACzC,CAAC,CAAC,CAAA;KACL;SAAM;QACH,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,oBAAoB,CAAC,CAAA;QAC5C,OAAO,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAA;KACzC;AACL,CAAC,CAAC,CAAA;AAEF,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,WAAW,CAAC,CAAA;AAC7B,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,CAAC,CAAA;AAE7B,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IAC3B,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,sBAAsB,CAAC,IAAI,GAAG,EAAC,CAAC,CAAA;AAC9E,CAAC,CAAC,CAAA;AAEF,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IACjC,GAAG,CAAC,MAAM,CAAC,SAAS,GAAG,CAAC,MAAM,CAAC,IAAI,UAAU,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,sBAAsB,CAAC,IAAI,GAAG,EAAC,CAAC,CAAA;AACzG,CAAC,CAAC,CAAA;AAEF,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IACjC,GAAG,CAAC,MAAM,CAAC,SAAS,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,sBAAsB,CAAC,IAAI,GAAG,EAAC,CAAC,CAAA;AACjG,CAAC,CAAC,CAAA;AAEF,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IACtB,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAA;IACtC,IAAI,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,sBAAsB,CAAC,IAAI,GAAG,CAAA;IACrD,GAAG,CAAC,QAAQ,CAAC,GAAG,IAAI,OAAO,CAAC,CAAA;AAChC,CAAC,CAAC,CAAA;AAEF,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IAC5B,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;IAC/B,KAAK,GAAG,EAAE,CAAA;IACV,GAAG,GAAG,MAAM,EAAE,CAAA;IACd,UAAU,GAAG,EAAE,CAAC,YAAY,CAAC,uBAAuB,CAAC,CAAC,QAAQ,EAAE,CAAA;IAChE,IAAI,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,sBAAsB,CAAC,IAAI,GAAG,CAAA;IACrD,GAAG,CAAC,QAAQ,CAAC,GAAG,IAAI,OAAO,CAAC,CAAA;AAChC,CAAC,CAAC,CAAA;AAEF,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAA;AAG1C,UAAU,GAAG,EAAE,CAAC,YAAY,CAAC,uBAAuB,CAAC,CAAC,QAAQ,EAAE,CAAA;AAChE,GAAG,GAAG,MAAM,EAAE,CAAA;AAEd,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE;IAClC,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAA;AACxC,CAAC,CAAC,CAAA;AACF,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA"}

View File

@ -1,21 +1,6 @@
<!-- { "toc": "compute", "title": "Projects - Just for Fun" } --> <!-- { "toc": "compute", "title": "Projects - Just for Fun" } -->
<h1>So ugly ... why not Wordpress?</h1>
<p>
I shut down my homepage at wordpress.com since it wasn't absolutely unclear to me which data was collected there. I decided to run the homepage on my own server again, since I know exactly which data is collected here: There is the Apache log with the requesters IP stripped away:
</p>
<p>
<pre>
CustomLog "logs/access_log" common
#LogFormat "%h %l %u %t \"%r\" %>s %b" common
LogFormat "%l %u %t \"%r\" %>s %b" common
</pre>
</p>
<p>
Nothing else. And since I'm quite bad in CSS, it currently looks so ugly.
</p>
<h1>My Blog</h1> <h1>My Blog</h1>

View File

@ -15,7 +15,8 @@
<div class="topnav"> <div class="topnav">
<a href="index">Home</a> <a href="index">Home</a>
<a href="pages/impressum">Impressum</a> <a href="pages/about">About</a>
<a href="pages/pubkey">PubKey</a>
</div> </div>
<div class="row"> <div class="row">
@ -25,7 +26,8 @@
</div> </div>
<div class="footer"> <div class="footer">
<a href="pages/impressum">Impressum</a> <a href="reload">Reload</a>
<a rel="me" href="https://ruhr.social/@wolutator">Mastodon</a>
</div> </div>
</body> </body>
</html> </html>

83
docroot/pages/about.pag Normal file
View File

@ -0,0 +1,83 @@
<!-- { "title": "About" } -->
<img class="floatright" src="files/IMG_6875_2-very-small.jpg"/>
<h1>About</h1>
Wolfgang Hottgenroth<br/>
<address>wolfgang.hottgenroth@icloud.com</address><br/>
<p>
This is a hobby-only homepage without any advertising or other commercial interests.
</p>
<h1>My Profiles</h1>
<ul>
<li><a href="https://gitlab.com/wolutator">GitLab</a></li>
<li><a href="https://home.hottis.de/gitlab/wolutator">GitLab</a></li>
<li><a href="https://twitter.com/wollud1969">Twitter</a></li>
<li><a href="https://keybase.io/wolutator/">Keybase</a></li>
<li><a href="https://github.com/wollud1969">GitHub</a></li>
<li><a href="https://www.xing.com/profile/Wolfgang_Hottgenroth/cv">XING</a></li>
</ul>
<h1>So ugly ... why not Wordpress?</h1>
<p>
I shut down my homepage at wordpress.com since it was absolutely unclear to me which data was collected there. I decided to run the homepage on my own server again.
</p>
<p>
Although according to Art. 2 (2) c of DSGVO that regulation is completely irrelevant for me, since this is a hobby-only blog without any advertising or commercial interests, it appeared to me, that limiting the number of collected data could be a good idea.
</p>
<p>
For this system I know exactly which data is collected here: There is the Apache httpd running on a Raspberry Pi with FreeBSD bastion host, which proxies
requests to the homepage engine.
</p>
<p>
The homepage engine is running in a Docker container on my small multi purpose server in the basement.
It just logs which post or page is accessed and served, nothing more.
If you like to have a look: <a href="https://home.hottis.de/gitlab/wolutator/homepage" target="_blank">https://home.hottis.de/gitlab/wolutator/homepage</a>.
</p>
<p>
The logging of the homepage engine looks like this:
</p>
<p>
<pre>
wn@mac:/opt/services/homepage$ npm start -- -c homepage.conf
> homepage@1.0.0 start /opt/services/homepage
> node dist/main.js "-c" "homepage.conf"
12:57:59.910 [ II ] Homepage starting
12:57:59.922 [ II ] building toc
12:57:59.937 [ II ] Homepage running
12:57:59.938 [ II ] Homepage is listening
12:58:19.008 [ II ] redirecting / to /index
12:58:19.142 [ II ] /opt/services/homepage/docroot/index.pag not yet in cache
12:58:24.178 [ II ] /opt/services/homepage/docroot/posts/2018-04-30.01/article.pag not yet in cache
12:58:25.550 [ II ] /opt/services/homepage/docroot/index.pag served from cache
12:58:26.985 [ II ] /opt/services/homepage/docroot/pages/impressum.pag not yet in cache
12:58:29.647 [ II ] /opt/services/homepage/docroot/index.pag served from cache
12:58:31.060 [ II ] /opt/services/homepage/docroot/posts/2018-02-22.01/article.pag not yet in cache
12:58:35.230 [ II ] /opt/services/homepage/docroot/index.pag served from cache
12:58:37.717 [ II ] /opt/services/homepage/docroot/index.pag served from cache
</pre>
</p>
<p>
And since I'm quite bad in CSS, it currently looks so ugly.
</p>
<p>
Furthermore, this homepage does not use any cookies.
</p>

View File

@ -1,5 +0,0 @@
<!-- { "title": "Impressum" } -->
<h1>Impressum</h1>
Wolfgang Hottgenroth<br/>
<address>woho@hottis.de</address><br/>

117
docroot/pages/pubkey.pag Normal file
View File

@ -0,0 +1,117 @@
<!-- { "title": "My Public PGP Key" } -->
<h1>#title#</h1>
<p>
<a href="files/9A0CD4EA597C9ABE371300816C1E5E531E0D5D7F.key">for download</a><br/>
<pre>
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
ZmdhbmcgSG90dGdlbnJvdGggPHdvaG9AaG90dGlzLmRlPokCTgQTAQgAOBYhBJoM
1OpZfJq+NxMAgWweXlMeDV1/BQJc+B2MAhsDBQsJCAcCBhUICQoLAgQWAgMBAh4B
AheAAAoJEGweXlMeDV1/b34P/A0ZLFKNZ7RXILqfAxW5aNURMNbRuc3Z1QJPmOQU
1WRjQt71yYcD1SVNwjW5NKTbueMWqS+I/pVIdgCVDhBxHhwnAl8Xq131hZ7+84TR
MGw/rsLx7dU3jmogpijqc8ghcMshuPXUDxEg6Qso0Bi4LrxdEvZaIDbXVaayhdrz
bJe8JVs7cXngnrtfIwwUhpc+YkA1v4DShygXPVvKFQtDuEwzbtdMvlKJNi1iuK5v
ssc6A3ANaQ532GsUlW/qtE/E2/QnbcBuV29gY+lezhDwU9IJY70lDxULL822APW5
623KgqooqjWo2O4LKFvxGNqDwe/QQltQbNEfRMOm9ugAjDYr/mUu8sZ+lVNXIvQ5
cp1IfzExG4htcuHwwQRcsHW5c/8VAbJZ2yoWS2klDDvqy3KxfZ6EsPd6/7yIWwrZ
m+d4O+ujQn/6NRHONNYPA2YH8sfbL+C3m02FyTVQO6ZzpLdlHKs9h2wd5aEw7MjH
JO05K/PyGaUn07J7z3pk8XcK8qf1FuCTooDSgQVqI0i3X7PWgtIhqKfvyJaspxxT
U4X8NHt95o1ZhWp8NPQlfTDLmxwU5QUrK8VZ5FxTStcdZZg+9OucBVVbrVQLLL2Y
Q80npcus3I90styh7tQwtzojkERr/WLwDfj3hahiCMFqLagLkg5nw10mwY0xY019
EILbuQINBFz3xHoBEADJ1rOpvyKpOXtTzMEEsWAYTLAzEle7EeqTUJpJcnqz+r5J
OBMhLxvuRmKRK2dU23gQicCHxmOQhNCd4b2d64G9QbngvJeyEv4IwgLxePNv5/LN
00PTk6rUNkApGcVU663tHXs8Q8Ux+R1zYk7UY86LIoBzC8lA21q5WktXl1qaAw85
a/fn9G/Vd+o+Gb8XS6OfCdmM9CGV1Gv3vnAJ+xytf+I5UIFXs+FExlWpWlcNGlYl
RFHAiHB/f/rvNJVnHamyipmfn6T3N809A+k9XVqmbhC1ymav1eYPfHCOtCFwMXmv
RgD7D2fNoJzu93cX8qPZLvyz0VOFuR1XVyshTKsxB4foXaqA6xhTtHBqn6F2Nz90
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
=xSlg
-----END PGP PUBLIC KEY BLOCK-----
</pre>
</p>
<h3>Fingerprint</h3>
<p>
<pre>
9A0C D4EA 597C 9ABE 3713 0081 6C1E 5E53 1E0D 5D7F
</pre>
</p>

View File

@ -1,23 +1,32 @@
define(`TITLE', `Something completely different: SNMP to MySQL') <!-- { "title": "Something completely different: SNMP to MySQL" } -->
define(`DATE', `2015-10-12') <h1>#title#</h1>
define(`CONTENT', ` <p>
I'm helping to maintain a fleet of about 50 printers in a charity distributed over about 30 locations in the city. Now, we wanted to know how much the individual printers are used to get some numbers for an effort to reduce the number of printers. I'm helping to maintain a fleet of about 50 printers in a charity distributed over about 30 locations in the city. Now, they wanted to know how much the individual printers are utilized to get some numbers for an effort to reduce the number of printers.
</p>
<p>
So, what is more self-evident then using SNMP to query the total page counter on a daily base - or better on an hourly base since the printers are switched off at this or that time and those we at least get sometimes valid data. So, what is more self-evident then using SNMP to query the total page counter on a daily base - or better on an hourly base since the printers are switched off at this or that time and those we at least get sometimes valid data.
</p>
<p>
Typical monitoring tools like Cacti or Zabbix are very good in drawing nice graphs but not so good in delivering absolute numbers. So I decided to write something on my own: query some devices for some SNMP data points and store the results in a database. Which devices and which data points and which combinations? Everything in the database too. Typical monitoring tools like Cacti or Zabbix are very good in drawing nice graphs but not so good in delivering absolute numbers. So I decided to write something on my own: query some devices for some SNMP data points and store the results in a database. Which devices and which data points and which combinations? Everything in the database too.
</p>
I looked for a SNMP library, first in Python, then in Java - since I'm quite familiar with these languages - but everything I found was rather complicated to use. Then I looked for something in C# and found ''SnmpSharpNet''. Still not that easy to use but easier then what I found in Python or Java. <p>
I looked for a SNMP library, first in Python, then in Java - since I'm quite familiar with these languages - but everything I found was rather complicated to use. Then I looked for something in C# and found ''SnmpSharpNet''. Still not that easy to use but much easier then what I found in Python or Java.
</p>
<p>
For that reason I started coding the little tool in C#. And what I did is working very well now. Configuration and error-handling is not perfect yet, but it is working. Enough for today. For that reason I started coding the little tool in C#. And what I did is working very well now. Configuration and error-handling is not perfect yet, but it is working. Enough for today.
</p>
<p>
BTW: I switched developing the code between Microsoft Visual Studio 2013 (on Windows) and Xamarin Studio (on the Mac) and run the tool on Linux. Works without any problem. Very nice! BTW: I switched developing the code between Microsoft Visual Studio 2013 (on Windows) and Xamarin Studio (on the Mac) and run the tool on Linux. Works without any problem. Very nice!
</p>
<!--more-->
<pre>
[code language="csharp"] <code language="csharp">
namespace Snmp2Mysql namespace Snmp2Mysql
{ {
@ -67,9 +76,11 @@ namespace Snmp2Mysql
} }
} }
} }
[/code] </code>
</pre>
[code language="SQL"] <pre>
<code language="SQL">
CREATE TABLE `device_t` ( CREATE TABLE `device_t` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`address` varchar(45) NOT NULL, `address` varchar(45) NOT NULL,
@ -107,14 +118,14 @@ CREATE TABLE `collecteddata_t` (
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `devicedataitem_fk_idx` (`devicedataitem`), KEY `devicedataitem_fk_idx` (`devicedataitem`),
CONSTRAINT `devicedataitem_fk` FOREIGN KEY (`devicedataitem`) REFERENCES `devicedataitem_t` (`id`) CONSTRAINT `devicedataitem_fk` FOREIGN KEY (`devicedataitem`) REFERENCES `devicedataitem_t` (`id`)
[/code] </code>
</pre>
And here are the sources: And here are the sources:
<a href="http://a385e-5.de/wp-content/uploads/Snmp2Mysql.zip">Snmp2Mysql</a> <a href="https://gitlab.com/wolutator/Snmp2Mysql.git">https://gitlab.com/wolutator/Snmp2Mysql.git</a>
I'm using GPL code from MySQL (the MySQL Connector for .NET), find it here <a href="http://dev.mysql.com/downloads/connector/net/" target="_blank">http://dev.mysql.com/downloads/connector/net/</a> and the SNMP library from <a href="http://www.snmpsharpnet.com" target="_blank">http://www.snmpsharpnet.com</a>. I'm using GPL code from MySQL (the MySQL Connector for .NET), find it here <a href="http://dev.mysql.com/downloads/connector/net/" target="_blank">http://dev.mysql.com/downloads/connector/net/</a> and the SNMP library from <a href="http://www.snmpsharpnet.com" target="_blank">http://www.snmpsharpnet.com</a>.
Ah, evaluation of the data? Haven't thought about, maybe using some tricky SQL statement or an Excel pivot table. I'll come back about that. Ah, evaluation of the data? Haven't thought about, maybe using some tricky SQL statement or an Excel pivot table. I'll come back about that.
')

View File

@ -0,0 +1,34 @@
<!-- { "title": "Why always SPI CS on pin 10?" } -->
<h1>#title#</h1>
<p>
Thank you, Ladyada, for <a href="https://learn.adafruit.com/adafruit-2-8-tft-touch-shield-v2">this great display</a>.
</p>
<p>
But why is TFT CS on pin 10?
</p>
<p>
<a href="files/bildschirmfoto-2016-03-03-um-21-48-49.png" rel="attachment wp-att-711"><img src="files/bildschirmfoto-2016-03-03-um-21-48-49.png" alt="Bildschirmfoto 2016-03-03 um 21.48.49" width="722" height="449" class="alignnone size-full wp-image-711" /></a>
</p>
<p>
Pin 10 is also the SPI CS for the Ethernet shield. Why not, for instance, pin 6:
</p>
<p>
<a href="files/img_1211-e1457038834523.jpg" rel="attachment wp-att-712"><img src="files/IMG_1211-e1457038834523-1024x768.jpg" alt="IMG_1211" width="474" height="356" class="alignnone size-large wp-image-712" /></a>
</p>
<p>
Carefully lift pin 9 of the level shifter and connect it using a thin wire with pin 6 of the Arduino connector.
</p>
<p>
And voila, both the display and the ethernet shield is working:
</p>
<p>
<a href="files/img_1212-e1457039094609.jpg" rel="attachment wp-att-713"><img src="files/IMG_1212-e1457039094609-1024x768.jpg" alt="IMG_1212" width="474" height="356" class="alignnone size-large wp-image-713" /></a>
</p>

View File

@ -0,0 +1,39 @@
<!-- { "title": "Integrated Thermometer and Timer" } -->
<h1>#title#</h1>
<p>
To brew green tea you need water of about 75°C. To know that your water has 100°C is easy, you can see that it is boiling. For 75°C you need a thermometer. Then you also need to take care about the brewing time. It should be usually two minutes.
</p>
<p>
There are such integrated thermometer and timer things on Amazon, but that's not me cup of tea, I decided to build one on my own. It should run on batteries, it should be small and it should make no noise (for office use).
</p>
<p>
In between I was reading "Patterns for Time-Triggered Embedded Systems" from Michael Pont. And afterwards I was curious to use such a simple cooperative scheduler instead of the super-loop, as it is common in the Arduino domain.
</p>
<p>
I used a MSP430G2553 with 10bit-ADCs, a PT1000 sensor and two seven-segment LED displays.
</p>
<p>
The code is available at <s><a href="https://bitbucket.org/wollud1969/teathermotimer" target="_blank">https://bitbucket.org/wollud1969/teathermotimer</a></s> <a href="https://gitlab.com/wolutator/TeaThermoTimer">https://gitlab.com/wolutator/TeaThermoTimer</a>.
</p>
<p>
<a href="files/img_0813-e1473432862286.jpg"><img src="files/img_0813-e1473432862286_small.jpg"/></a>
</p>
<p>
<a href="files/img_0814.jpg"><img src="files/img_0814_small.jpg" /></a>
</p>
<p>
Schematics:<br/>
<a href="files/201609091558_0001.pdf">201609091558_0001</a>
</p>
<p>
Calculation for measurement:<br/>
<a href="files/201609091558_0002.pdf">201609091558_0002</a>
</p>

View File

@ -0,0 +1,29 @@
<!-- { "title": "Integrated Tea Timer and Thermometer, Second Edition" } -->
<h1>#title#</h1>
<p>
I've two offices, so I'm requiring two of this timers.
</p>
<p>
The second one I built with a three-digit display and auto-power-down and start with a push-button.
</p>
<p>
This thing consumes in operation about 20mA, which is a real lot for so few functionality, but most of the power goes into the display. I was looking for a simple LCD on ebay, but it seems that most of the LCD 7-segment display have only one common and one pin for every single segment instead of one common per digit. These are too many pins for the 2553 and I didn't want to put an additional LCD controller on the board.
</p>
<p>
However, when the thing goes in LPM4, it only consumes about 0,1uA, as it is written in the datasheet. Very important to achieve this low power consumption: an input pin requires more power than an output pin put into the right level. And of course the reference generator of the ADC needs to be shutdown.
</p>
<p>
The sources are still available here <s>https://bitbucket.org/wollud1969/teathermotimer</s> <a href="https://gitlab.com/wolutator/TeaThermoTimer/tree/SecondEdition">https://gitlab.com/wolutator/TeaThermoTimer/tree/SecondEdition</a>, look for the branch <code>SecondEdition</code>.
</p>
<p>
The schematic is more or less the same, just on digit display more and a reset push-button.
</p>
<a href="files/img_0818-e1473677307841.jpg"><img src="files/img_0818-e1473677307841_small.jpg"/></a>
<a href="files/img_0821-e1473677332189.jpg"><img src="files/img_0821-e1473677332189_small.jpg"/></a>

View File

@ -0,0 +1,83 @@
<!-- { "title": "Three Phase Inverter" } -->
<h1>#title#</h1>
<p>
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.
</p>
<p>
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 this time I was able with three phases to drive an asynchronous motor.
</p>
<p>
<a href="files/img_0053.jpg"><img src="files/img_0053.jpg" alt="img_0053" width="730" height="973"/></a>
</p>
<p>
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.
</p>
<p>
<a href="files/img_0054-e1476437702547.jpg"><img src="files/img_0054-e1476437702547.jpg" alt="img_0054" width="730" height="548"/></a>
</p>
<p>
The bridge is a three phase IGBT module is a 6MB120F-060 I got for a few euros at ebay.
</p>
<p>
<a href="files/img_0055-e1476437685461.jpg"><img src="files/img_0055-e1476437685461.jpg" alt="img_0055" width="730" /></a>
</p>
<p>
To avoid high voltages in my setup I got a 24V async motor, also from ebay.
</p>
<p>
<a href="files/img_0056.jpg"><img src="files/img_0056.jpg" alt="img_0056" width="730" height="548" /></a>
</p>
<p>
The PWMs generate the signal from a sine table generated using Excel. Those I got this signal:
</p>
<p>
<a href="files/inverter0_2016-09-23-4.png"><img src="files/inverter0_2016-09-23-4.png" alt="inverter0_2016-09-23-4" width="640" /></a>
</p>
<p>
The main task of the coordinator is the start the PWMs with a phase shift of 120° (digital line 1, 2 and 3):
</p>
<p>
<a href="files/10/2016-10-13_1.png"><img src="files/2016-10-13_1.png" alt="2016-10-13_1" width="640" height="520" /></a>
</p>
<p>
Currently the PWMs start with random polarity. The interesting signals are the digital lines 4, 5 and 6.
</p>
<p>
Sometimes the motor runs:
</p>
<p>
<a href="files/2016-10-13_works.png"><img src="files/2016-10-13_works.png" alt="2016-10-13_works" width="640" height="520" /></a>
</p>
<p>
But sometimes not:
</p>
<p>
<a href="files/2016-10-13_works_not.png"><img src="files/2016-10-13_works_not.png" alt="2016-10-13_works_not" width="640" /></a>
</p>
<p>
<s>
The firmware is available on bitbucket, for the PWM controllers <a href="https://bitbucket.org/wollud1969/inverter0.git" target="_blank">here</a> and for the coordinator <a href="https://bitbucket.org/wollud1969/inverter0ctrl.git" target="_blank">here</a>.
</s>
</p>
<p>
The firmware is available on Gitlab, for the PWM controllers <a href="https://gitlab.com/wolutator/inverter0" target="_blank">here</a> and for the coordinator <a href="https://gitlab.com/wolutator/inverter0ctrl" target="_blank">here</a>.
</p>

View File

@ -0,0 +1,67 @@
<!-- { "title": "Something really useful: 433MHz Power-Outlet Control" } -->
<h1>#title#</h1>
<p>
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.)
</p>
<p>
Now I was looking for a way to
<ol>
<li>Control the switches from different manufacturers with one remote.</li>
<li>Control them from really remote - from the office or from holiday.</li>
<li>Control them programmatically.</li>
</ol>
There are a couple of Arduino libraries out there which are working with this cheap 433MHz senders and receivers from China:
<img src="files/sender_receiver.png" alt="sender_receiver" width="406" height="386" /><br/>
I tried several ones, not all a really working, but finally I stopped at <a href="https://github.com/sui77/rc-switch" target="_blank">https://github.com/sui77/rc-switch</a>, which works really good.
</p>
<p>
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:
</p>
<p>
<a href="files/img_01012-e1478087121580.jpg"><img src="files/img_01012-e1478087121580.jpg?w=730" alt="img_0101" width="730" height="548" /></a><
</p>
<p>
<a href="files/img_0105.jpg"><img src="files/img_0105.jpg?w=730" alt="img_0105" width="730" height="548"/></a>
</p>
<p>
Software for this thing can be found here <a href="https://gitlab.com/wolutator/433Receiver.git" target="_blank">https://gitlab.com/wolutator/433Receiver.git</a>.
</p>
<p>
This is how it works:
</p>
<p>
<a href="files/img_0111-e1478087101747.jpg"><img src="files/img_0111-e1478087101747.jpg?w=730" alt="img_0111" width="730" height="548"/></a>
</p>
<p>
The second challenge is to send the codes out into air and let the power switches receive them. This is done with this thing:
</p>
<p>
<a href="files/img_0100-e1478087375824.jpg"><img src="files/img_0100-e1478087375824.jpg?w=730" alt="img_0100" width="730" height="548" /></a>
</p>
<p>
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.
</p>
<p>
This thing received messages via MQTT and send them out via 433MHz.
</p>
<p>
The software is <a href="https://gitlab.com/wolutator/Mqtt433Gateway.git" target="_blank">here at Gitlab</a>.
</p>
<p>
BTW: do not expect beautiful software, this has been made on Halloween evening and night when waiting for the kids to come home.
</p>

View File

@ -0,0 +1,48 @@
<!-- { "title": "Three Phase Inverter, Second Service" } -->
<h1>#title#</h1>
<p>
I wrote in October about my first try to build a simple three phase inverter, see <a href="posts/2016-10-14.01" target="_blank">here</a>. 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.
</p>
<p>
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.
</p>
<p>
<a href="files/img_0140.jpg">
<img src="files/img_0140_small.jpg"/>
</a>
</p>
<p>
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.
</p>
<p>
<a href="files/img_0144.jpg">
<img src="files/img_0144__small.jpg"/>
</a>
</p>
<p>
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.
</p>
<p>
<a href="files/img_0146.jpg">
<img src="files/img_0146_small.jpg"/>
</a>
</p>
<p>
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:
</p>
<p>
<a href="files/img_0143-e1482141676335.jpg"><img src="files/img_0143-e1482141676335_small.jpg"/></a>
</p>
<p>
(Some space reserved for a HMI unit to be connected via CAN ...)
</p>

View File

@ -1,4 +1,6 @@
<!-- { "title": "Configuration-Webserver for ESP8266 Projects" } --> <!-- { "title": "Configuration-Webserver for ESP8266 Projects" } -->
<h1>#title#</h1>
<p> <p>
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. 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.
</p> </p>
@ -41,270 +43,14 @@ open('configuration.cpp','w').write(str(c_file))
</p> </p>
<p> <p>
The two templates are: Using the both templates for a <a href="https://gitlab.com/wolutator/EspThermometer2/blob/master/ConfigGenerator/configuration_c.tmpl" target="_blank">C-</a> and a <a href="https://gitlab.com/wolutator/EspThermometer2/blob/master/ConfigGenerator/configuration_h.tmpl" target="_blank">H-</a>file all the code for the configuration web page, the EEPROM handling code and the code to access the configuration variables is generated.
</p> </p>
<p> <p>
<pre> The functions provided using these templates in turn a call from a rather simple <a href="https://gitlab.com/wolutator/EspThermometer2/blob/master/configurationMode.cpp" target="_blank">configuration mode</a>. In pure configuration mode (when the device is unconfigured or the configuration mode is requested using a pulled-down pin) a new WLAN will be opened using the accesspoint functionality of the ESP8266. In production mode, the configuration accesspoint is not started, however, the configuration mode webserver is started nevertheless.
<code "language"="C">
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>
</pre>
</p> </p>
<p> <p>
And: This code can be also found embedded in several of my projects. Find them at <a href="https://gitlab.com/wolutator/EspThermometer2" target="_blank">https://gitlab.com/wolutator/EspThermometer2</a>, <a href="https://gitlab.com/wolutator/TouchSwitch" target="_blank">https://gitlab.com/wolutator/TouchSwitch</a>, <a href="https://gitlab.com/wolutator/MySwitch" target="_blank">https://gitlab.com/wolutator/MySwitch</a>, <a href="https://gitlab.com/wolutator/RainSensor" target="_blank">https://gitlab.com/wolutator/RainSensor</a> and <a href="https://gitlab.com/wolutator/TwoLedSignal" target="_blank">https://gitlab.com/wolutator/TwoLedSignal</a>.
</p>
<p>
<pre>
<code language="C">
#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>
</pre>
</p>
<p>
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.
</p>
<p>
Since I'm programming the ESP8266 in an Eclipse-based Arduino-environment, this is all done in the <code>setup()</code> and <code>loop()</code> function:
</p>
<p>
<pre>
<code language="C">
// Do not remove the include below
#include "EspThermometer2.h"
#include "defines.h"
// #define ESP8266
#include <EEPROM.h>
#include "configuration.h"
#include "productionMode.h"
#include "configurationMode.h"
ADC_MODE(ADC_VCC);
bool configMode = false;
uint32_t startTime = 0;
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);
setupConfigurationNetwork();
setupConfigurationServer();
} else {
#ifdef DEBUG
Serial.println("Production mode");
Serial.println();
Serial.println();
showConfiguration();
#endif
digitalWrite(LED_PIN, HIGH);
setupProduction();
setupConfigurationServer();
}
#ifdef DEBUG
Serial.println("Started.");
#endif
}
void loop() {
if (configMode) {
loopConfiguration();
} else {
loopProduction();
}
}
</code>
</pre>
</p>
<p>
This code can be also found embedded into two of my projects. Find them at <a href="https://gitlab.com/wolutator/EspThermometer2" target="_blank">https://gitlab.com/wolutator/EspThermometer2</a> and <a href="https://gitlab.com/wolutator/TouchSwitch" target="_blank">https://gitlab.com/wolutator/TouchSwitch</a>.
</p> </p>

View File

@ -0,0 +1,81 @@
<!-- { "title": "From InfluxDB to Twitter - daily temperature tweet" } -->
<h1>#title#</h1>
<p>
This is my first attempt to build a tweetbot. I'm using node-red both as development and runtime environment. It comes with dedicated plugins for both InfluxDB and Twitter.
</p>
<p>
The whole flow of the tweetbot is this:
<img src="files/Screenshot_2019-01-04_08-28-39.png" width="1200"/>
</p>
<p>
It starts with an inject node "Daily at noon" (<a href="files/Screenshot_2019-01-04_08-29-24.png" target="_blank">*</a>), with triggers the whole flow once a day at high noon.
</p>
<p>
The four influx query nodes read data from the InfluxDB using the following queries, each one encapsulated in one influx query node:
<pre><code class="SQL">
select mean(pv) from measured where deviceid = 'Hedge' and kind = 'Temperature' and time > now() - 15m
select mean(pv) from measured where deviceid = 'Hedge' and kind = 'Temperature' and time > now() - 24h
select min(pv) from measured where deviceid = 'Hedge' and kind = 'Temperature' and time > now() - 24h
select max(pv) from measured where deviceid = 'Hedge' and kind = 'Temperature' and time > now() - 24h
</code></pre>
See one of this node <a href="files/Screenshot_2019-01-04_08-29-47.png" target="_blank">here</a>.
</p>
<p>
The data in the InfluxDB considered by these queries looks like this:
<pre>
> select * from measured where kind = 'Temperature' and deviceid = 'Hedge' limit 10
name: measured
time category deviceid kind pv qv sv tv
---- -------- -------- ---- -- -- -- --
2018-12-24T12:57:42.749065469Z Outdoor Hedge Temperature 5.029083728790283 -1
2018-12-24T12:58:54.77913537Z Outdoor Hedge Temperature 5.020352363586426 -1
2018-12-24T13:00:06.754460483Z Outdoor Hedge Temperature 5.032242298126221 -1
2018-12-24T13:01:18.76525238Z Outdoor Hedge Temperature 5.024284362792969 -1
2018-12-24T13:02:30.767286588Z Outdoor Hedge Temperature 5.016140937805176 -1
2018-12-24T13:03:42.765550192Z Outdoor Hedge Temperature 5.0108466148376465 -1
2018-12-24T13:04:54.774511705Z Outdoor Hedge Temperature 5.019856929779053 -1
2018-12-24T13:06:05.772434549Z Outdoor Hedge Temperature 5.020042419433594 -1
2018-12-24T13:07:16.759739681Z Outdoor Hedge Temperature 5.036855697631836 -1
2018-12-24T13:08:27.757626686Z Outdoor Hedge Temperature 4.993878364562988 -1
>
</pre>
<code>pv</code> has the temperature, <code>sv</code> has the battery voltage. In this case it is -1 since this particular thermometer is powered by a power supply from mains.
</p>
<p>
In the following four change nodes (<a href="files/Screenshot_2019-01-04_08-30-06.png" target="_blank">*</a>) a dedicated topic for the messages from the influx query nodes will be set to merge them into a single key/value object in the following join node (<a href="files/Screenshot_2019-01-04_08-30-27.png" target="_blank">*</a>). This node will collect four messages and put them into a single object with the topic as key and the message as value.
</p>
<p>
This object in turn is input for the function node "TextPreparator" (<a href="files/Screenshot_2019-01-04_08-30-48.png" target="_blank">*</a>) where the tweet is prepared using a small snippet of JavaScript code:
<pre><code class="JavaScript">
let output = ""
output += `Die aktuelle Temperatur zuhause ist ${msg.payload.avg15min[0].mean.toFixed(1)}°C.\n`
output += `Die Durchschnittstemperatur der letzten 24 Stunden war ${msg.payload.avg24h[0].mean.toFixed(1)}°C, `
output += `die Tiefsttemperatur war ${msg.payload.min[0].min.toFixed(1)}°C um ${msg.payload.min[0].time.getHours()}:${msg.payload.min[0].time.getMinutes()} Uhr und `
output += `die Höchsttemperatur war ${msg.payload.max[0].max.toFixed(1)}°C um ${msg.payload.max[0].time.getHours()}:${msg.payload.max[0].time.getMinutes()} Uhr.\n`
output += "Powered by @NodeRED and @InfluxDB."
msg.payload = output
return msg;
</code></pre>
</p>
<p>
Finally this text will be sent to Twitter via the node "Tweet" (<a href="files/Screenshot_2019-01-04_08-31-06.png" target="_blank">*</a>). Done.
</p>
<p>
<img src="files/Screenshot_2019-01-04_09-08-07.png"/>
</p>

View File

@ -0,0 +1,49 @@
<!-- { "title": "SSH Key Forwarding meets Screen" } -->
<h1>#title#</h1>
<p>
I'm using both SSH key forwarding and screen a lot. Since I discovered Nitrokey, the OpenPGP card and Yubikey, all my SSH keys are on those tokens.
It works perfectly: You authenticated using the token in the laptop and use that key over a whole chain of machines and in some cases and the third or fourth machine in a row to pull and push to git.
</p>
<p>
I'm also using screen a lot. I set up a bunch of related sessions, sometimes on different machine in one screen session, detach from it, use it again the next day and so on.
Also works fine. Longwinding login processes, especially when bastion hosts and jump hosts are involved can be avoided.
However, at least out of the box, SSH key forwarding does not work in this setup. Suddenly ssh asks for passwords. Ugh!
</p>
<p>
Google was my friend and I found this page: <a href="https://gist.github.com/martijnvermaat/8070533">https://gist.github.com/martijnvermaat/8070533</a>. Martijn explains an easy solution to address this problem.
Not to forget it again I will summarize it here.
</p>
<p>
<ol>
<li>Create a file <tt>~/.screenrc</tt> and put
<pre><code class="shell">
setenv SSH_AUTH_SOCK $HOME/.ssh/SSH_AUTH_SOCK
</code></pre>
into it. If you are using bash, don't be tempted to write <tt>export</tt> instead of <tt>setenv</tt>, it won't work.
</li>
<li>
Create a file <tt>~/.ssh/rc</tt> and put
<pre><code class="shell">
if test "$SSH_AUTH_SOCK" ; then
ln -sf $SSH_AUTH_SOCK ~/.ssh/ssh_auth_sock
fi
</code></pre>
into it.
</li>
<li>Restart the screen session, done. Works perfectly for me.</li>
</ol>

View File

@ -0,0 +1,102 @@
<!-- { "title": "Migrating a Grafana configuration database from SQLite to MySQL/MariaDB" } -->
<h1>#title#</h1>
<p>
In the default installation <a href="https://grafana.com">Grafana</a> is using a SQLite database for its configuration and session data. Certainly, this is working very well in most situations.
</p>
<p>
Nevertheless I preferred to use my anyhow existing MariaDB server.
</p>
<p>
So, I had to migrate the already existing SQLite database containing the Grafana configuration to MySQL syntax. Not to difficult, but at least it was not working without some adjustments. I found some hints how to do this migration. However, at least one hint I found more than once pointed to a paid migration service - no, thank you.
</p>
<p>
I think for text processing using regular expressions Perl is the language of choice. so I prepared a small processing frame:
<pre><code class="perl">
#!/usr/bin/perl -w
use strict;
while (<>) {
chomp;
print "$_\n";
}
</code></pre>
</p>
<p>
I deployed a dedicated test instance of a MariaDB server using Docker on my laptop, created a database on that MariaDB server
<pre><code class="SQL">
create database grafana;
create user 'grafana'@'%' identified by 'test123';
grant all privileges on grafana.* to 'grafana'@'%';
flush privileges;
</code></pre>
and used a small shell script to export the SQLite database into a SQL file, pass it through the above Perl script and feed it into the MariaDB server:
<pre><code class="shell">
#!/bin/bash
DB_HOST=127.0.0.1
DB_ROOT_PASS=geheim123
DB_NAME=grafana
DB_USER=grafana
DB_PASS=test123
cat grafana.in | sqlite3 grafana.db && \
cat grafana.sql | ./sqlite2mariadb.pl > new.sql && \
echo "drop database $DB_NAME; create database $DB_NAME;' | \
mysql -h $DB_HOST -u root --password=$DB_ROOT_PASS mysql && \
cat new.sql | mysql -h $DB_HOST -u $DB_USER --password=$DB_PASS --abort-source-on-error -v $DB_NAME
</code></pre>
</p>
<p>
Inspecting the error messages from the import into the MariaDB I extended the Perl script more and more and finally ended up with this code:
<pre><code class="perl">
#!/usr/bin/perl -w
use strict;
while (<>) {
chomp;
s/^BEGIN TRANSACTION;//;
s/^PRAGMA .+?;//;
s/AUTOINCREMENT/AUTO_INCREMENT/;
s/TEXT PRIMARY KEY/VARCHAR(1024) PRIMARY KEY/;
s/` TEXT /` MEDIUMTEXT /;
s/`for` INTEGER/`for` BIGINT/;
s/`frequency` INTEGER/`frequency` BIGINT/;
s/`epoch` INTEGER/`epoch` BIGINT/;
s/`epoch_end` INTEGER/`epoch_end` BIGINT/;
s/`created` INTEGER/`created` BIGINT/;
s/`updated` INTEGER/`updated` BIGINT/;
s/^.+? sqlite_sequence.*$//;
s/^CREATE INDEX `.+$//;
print "$_\n";
}
</code></pre>
</p>
<p>
Maybe on a different installation or using a future version of Grafana you would run into more issues. In that case: just put additional substitutions into the script.
</p>
<p>
When the whole stuff ran through without errors I backupped the configuration and storage volumes of my Grafana container, created new ones with copies of the old ones. I removed the <tt>grafana.db</tt> file from the storage volume and modified the <tt>grafana.ini</tt> in the configuration volume to use the MariaDB server, loaded the transformed SQL into the productive MariaDB server and restarted the Grafana container with the new volumes.
</p>
<p>
Suprisingly it works immediately.
</p>

View File

@ -0,0 +1,8 @@
<!-- { "title": "Wiki created" } -->
<h1>#title#</h1>
<p>
At <a href="https://home.hottis.de/dokuwiki/">https://home.hottis.de/dokuwiki/</a> a local wiki can be found now.
</p>

View File

@ -0,0 +1,22 @@
<!-- { "title": "Mains Frequency Measurement Project" } -->
<h1>#title#</h1>
<p>
The homepage of my "Mains Frequency Measurement Project" is at <a href="https://wiki.mainscnt.eu">https://wiki.mainscnt.eu/</a>.
</p>
<p>
Measurements from already seven locations all over Europe are collected in the project's database and displayed in one visualization at <a href="https://grafana.mainscnt.eu">https://grafana.mainscnt.eu</a>.
</p>
<p>
More data contributions are welcome.
</p>
<p>
Access to the collected data can be granted. Just contact me.
</p>
<p>
<img src="files/IMG_2507.jpg" width="300"/>
</p>

BIN
files/2016-10-13_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

BIN
files/2016-10-13_works.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

BIN
files/201609091558_0001.pdf Normal file

Binary file not shown.

BIN
files/201609091558_0002.pdf Normal file

Binary file not shown.

View File

@ -0,0 +1,115 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
UzZbs54AnA==
=GSFz
-----END PGP PUBLIC KEY BLOCK-----

View File

@ -0,0 +1,101 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
ZmdhbmcgSG90dGdlbnJvdGggPHdvaG9AaG90dGlzLmRlPokCTgQTAQgAOBYhBJoM
1OpZfJq+NxMAgWweXlMeDV1/BQJc+B2MAhsDBQsJCAcCBhUICQoLAgQWAgMBAh4B
AheAAAoJEGweXlMeDV1/b34P/A0ZLFKNZ7RXILqfAxW5aNURMNbRuc3Z1QJPmOQU
1WRjQt71yYcD1SVNwjW5NKTbueMWqS+I/pVIdgCVDhBxHhwnAl8Xq131hZ7+84TR
MGw/rsLx7dU3jmogpijqc8ghcMshuPXUDxEg6Qso0Bi4LrxdEvZaIDbXVaayhdrz
bJe8JVs7cXngnrtfIwwUhpc+YkA1v4DShygXPVvKFQtDuEwzbtdMvlKJNi1iuK5v
ssc6A3ANaQ532GsUlW/qtE/E2/QnbcBuV29gY+lezhDwU9IJY70lDxULL822APW5
623KgqooqjWo2O4LKFvxGNqDwe/QQltQbNEfRMOm9ugAjDYr/mUu8sZ+lVNXIvQ5
cp1IfzExG4htcuHwwQRcsHW5c/8VAbJZ2yoWS2klDDvqy3KxfZ6EsPd6/7yIWwrZ
m+d4O+ujQn/6NRHONNYPA2YH8sfbL+C3m02FyTVQO6ZzpLdlHKs9h2wd5aEw7MjH
JO05K/PyGaUn07J7z3pk8XcK8qf1FuCTooDSgQVqI0i3X7PWgtIhqKfvyJaspxxT
U4X8NHt95o1ZhWp8NPQlfTDLmxwU5QUrK8VZ5FxTStcdZZg+9OucBVVbrVQLLL2Y
Q80npcus3I90styh7tQwtzojkERr/WLwDfj3hahiCMFqLagLkg5nw10mwY0xY019
EILbuQINBFz3xHoBEADJ1rOpvyKpOXtTzMEEsWAYTLAzEle7EeqTUJpJcnqz+r5J
OBMhLxvuRmKRK2dU23gQicCHxmOQhNCd4b2d64G9QbngvJeyEv4IwgLxePNv5/LN
00PTk6rUNkApGcVU663tHXs8Q8Ux+R1zYk7UY86LIoBzC8lA21q5WktXl1qaAw85
a/fn9G/Vd+o+Gb8XS6OfCdmM9CGV1Gv3vnAJ+xytf+I5UIFXs+FExlWpWlcNGlYl
RFHAiHB/f/rvNJVnHamyipmfn6T3N809A+k9XVqmbhC1ymav1eYPfHCOtCFwMXmv
RgD7D2fNoJzu93cX8qPZLvyz0VOFuR1XVyshTKsxB4foXaqA6xhTtHBqn6F2Nz90
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
=xSlg
-----END PGP PUBLIC KEY BLOCK-----

BIN
files/IMG_0536.JPG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 KiB

BIN
files/IMG_2507.JPG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 959 KiB

BIN
files/IMG_2507.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
files/IMG_6875_2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -1,8 +1,9 @@
body { body {
font-family: "verdana", sans-serif; font-family: "Optima", sans-serif;
font-size: 16px; font-size: 16px;
margin: 0 5% 0 5%; margin: 20px 10% 0 10%;
width: 1080px; width: 80%;
background-color: lightblue;
} }
.header { .header {
@ -33,6 +34,7 @@ body {
.main { .main {
padding: 15px; padding: 15px;
background-color: whitesmoke;
} }
.row:after { .row:after {
@ -43,14 +45,14 @@ body {
.footer { .footer {
font-size: 12px; font-size: 12px;
background-color: #f1f1f1; background-color: #333;
overflow: hidden; overflow: hidden;
} }
.footer a { .footer a {
float: left; float: left;
display: block; display: block;
color: #333; color: #f2f2f2;
text-align: center; text-align: center;
padding: 14px 16px; padding: 14px 16px;
text-decoration: none; text-decoration: none;
@ -60,3 +62,8 @@ body {
background-color: #ddd; background-color: #ddd;
color: black; color: black;
} }
.floatright {
float: right;
padding-top: 25px;
}

241
files/hm-config.txt Normal file
View File

@ -0,0 +1,241 @@
MASTER
{
Channel: 2
{
[TRANSMIT_TRY_MAX]: 06
[AES_ACTIVE]: 00
[POWERUP_ACTION]: 00
[STATUSINFO_RANDOM]: 01
[STATUSINFO_MINDELAY]: 04
}
Channel: 1
{
[TRANSMIT_TRY_MAX]: 06
[AES_ACTIVE]: 00
[POWERUP_ACTION]: 00
[STATUSINFO_RANDOM]: 01
[STATUSINFO_MINDELAY]: 04
}
Channel: 0
{
[ROAMING]: 00
[POLLING_INTERVAL]: 3c
[CONF_BUTTON_TIME]: ff
[INTERNAL_KEYS_VISIBLE]: 01
[POLLING]: 00
[LOCAL_RESET_DISABLE]: 00
}
}
VALUES
{
Channel: 2
{
[WORKING]: 00
[INHIBIT]: 00
[STATE]: 00
[INSTALL_TEST]: 00
[ON_TIME]: 00
}
Channel: 1
{
[WORKING]: 00
[INHIBIT]: 00
[STATE]: 00
[INSTALL_TEST]: 00
[ON_TIME]: 00
}
Channel: 0
{
[CENTRAL_ADDRESS_SPOOFED]: 00
[RSSI_PEER]: 00
[BOOT]: 00
[RSSI_DEVICE]: 3a
[AES_KEY]: 00
[CONFIG_PENDING]: 00
[LAST_PACKET_RECEIVED]: 5b 16 17 7e
[DUTYCYCLE]: 00
[UNREACH]: 00
[LOWBAT]: 00
[STICKY_UNREACH]: 01
}
}
LINK
{
Channel: 2
{
Address: 0xfd0001
{
Remote channel: 2
{
[UI_HINT]: 00
[SHORT_ON_TIME]: ff
[SHORT_ONDELAY_TIME]: 00
[SHORT_OFF_TIME]: ff
[SHORT_OFFDELAY_TIME]: 00
[SHORT_JT_ONDELAY]: 06
[SHORT_JT_ON]: 06
[SHORT_JT_OFFDELAY]: 06
[SHORT_JT_OFF]: 06
[SHORT_CT_ONDELAY]: 00
[SHORT_CT_OFFDELAY]: 00
[LONG_JT_OFF]: 06
[SHORT_ON_TIME_MODE]: 00
[LONG_ONDELAY_TIME]: 00
[SHORT_CT_ON]: 00
[LONG_CT_ONDELAY]: 00
[LONG_ACTION_TYPE]: 01
[LONG_COND_VALUE_HI]: 64
[LONG_OFF_TIME_MODE]: 00
[LONG_OFFDELAY_TIME]: 00
[LONG_CT_OFFDELAY]: 00
[SHORT_COND_VALUE_LO]: 32
[LONG_COND_VALUE_LO]: 32
[LONG_CT_OFF]: 00
[LONG_JT_ONDELAY]: 06
[SHORT_OFF_TIME_MODE]: 00
[LONG_CT_ON]: 00
[LONG_MULTIEXECUTE]: 01
[SHORT_CT_OFF]: 00
[LONG_OFF_TIME]: ff
[LONG_JT_OFFDELAY]: 06
[LONG_ON_TIME_MODE]: 00
[LONG_JT_ON]: 06
[LONG_ON_TIME]: ff
[SHORT_ACTION_TYPE]: 01
[SHORT_COND_VALUE_HI]: 64
}
}
Address: 0x5a518b
{
Remote channel: 2
{
[UI_HINT]: 00
[SHORT_ON_TIME]: ff
[SHORT_ONDELAY_TIME]: 00
[SHORT_OFF_TIME]: ff
[SHORT_OFFDELAY_TIME]: 00
[SHORT_JT_ONDELAY]: 03
[SHORT_JT_ON]: 04
[SHORT_JT_OFFDELAY]: 06
[SHORT_JT_OFF]: 01
[SHORT_CT_ONDELAY]: 00
[SHORT_CT_OFFDELAY]: 00
[LONG_JT_OFF]: 01
[SHORT_ON_TIME_MODE]: 00
[LONG_ONDELAY_TIME]: 00
[SHORT_CT_ON]: 00
[LONG_CT_ONDELAY]: 00
[LONG_ACTION_TYPE]: 01
[LONG_COND_VALUE_HI]: 64
[LONG_OFF_TIME_MODE]: 00
[LONG_OFFDELAY_TIME]: 00
[LONG_CT_OFFDELAY]: 00
[SHORT_COND_VALUE_LO]: 32
[LONG_COND_VALUE_LO]: 32
[LONG_CT_OFF]: 00
[LONG_JT_ONDELAY]: 03
[SHORT_OFF_TIME_MODE]: 00
[LONG_CT_ON]: 00
[LONG_MULTIEXECUTE]: 01
[SHORT_CT_OFF]: 00
[LONG_OFF_TIME]: ff
[LONG_JT_OFFDELAY]: 06
[LONG_ON_TIME_MODE]: 00
[LONG_JT_ON]: 04
[LONG_ON_TIME]: ff
[SHORT_ACTION_TYPE]: 01
[SHORT_COND_VALUE_HI]: 64
}
}
}
Channel: 1
{
Address: 0xfd0001
{
Remote channel: 1
{
[UI_HINT]: 00
[SHORT_ON_TIME]: ff
[SHORT_ONDELAY_TIME]: 00
[SHORT_OFF_TIME]: ff
[SHORT_OFFDELAY_TIME]: 00
[SHORT_JT_ONDELAY]: 06
[SHORT_JT_ON]: 06
[SHORT_JT_OFFDELAY]: 06
[SHORT_JT_OFF]: 06
[SHORT_CT_ONDELAY]: 00
[SHORT_CT_OFFDELAY]: 00
[LONG_JT_OFF]: 06
[SHORT_ON_TIME_MODE]: 00
[LONG_ONDELAY_TIME]: 00
[SHORT_CT_ON]: 00
[LONG_CT_ONDELAY]: 00
[LONG_ACTION_TYPE]: 01
[LONG_COND_VALUE_HI]: 64
[LONG_OFF_TIME_MODE]: 00
[LONG_OFFDELAY_TIME]: 00
[LONG_CT_OFFDELAY]: 00
[SHORT_COND_VALUE_LO]: 32
[LONG_COND_VALUE_LO]: 32
[LONG_CT_OFF]: 00
[LONG_JT_ONDELAY]: 06
[SHORT_OFF_TIME_MODE]: 00
[LONG_CT_ON]: 00
[LONG_MULTIEXECUTE]: 01
[SHORT_CT_OFF]: 00
[LONG_OFF_TIME]: ff
[LONG_JT_OFFDELAY]: 06
[LONG_ON_TIME_MODE]: 00
[LONG_JT_ON]: 06
[LONG_ON_TIME]: ff
[SHORT_ACTION_TYPE]: 01
[SHORT_COND_VALUE_HI]: 64
}
}
Address: 0x5a518b
{
Remote channel: 1
{
[UI_HINT]: 00
[SHORT_ON_TIME]: ff
[SHORT_ONDELAY_TIME]: 00
[SHORT_OFF_TIME]: ff
[SHORT_OFFDELAY_TIME]: 00
[SHORT_JT_ONDELAY]: 03
[SHORT_JT_ON]: 04
[SHORT_JT_OFFDELAY]: 06
[SHORT_JT_OFF]: 01
[SHORT_CT_ONDELAY]: 00
[SHORT_CT_OFFDELAY]: 00
[LONG_JT_OFF]: 01
[SHORT_ON_TIME_MODE]: 00
[LONG_ONDELAY_TIME]: 00
[SHORT_CT_ON]: 00
[LONG_CT_ONDELAY]: 00
[LONG_ACTION_TYPE]: 01
[LONG_COND_VALUE_HI]: 64
[LONG_OFF_TIME_MODE]: 00
[LONG_OFFDELAY_TIME]: 00
[LONG_CT_OFFDELAY]: 00
[SHORT_COND_VALUE_LO]: 32
[LONG_COND_VALUE_LO]: 32
[LONG_CT_OFF]: 00
[LONG_JT_ONDELAY]: 03
[SHORT_OFF_TIME_MODE]: 00
[LONG_CT_ON]: 00
[LONG_MULTIEXECUTE]: 01
[SHORT_CT_OFF]: 00
[LONG_OFF_TIME]: ff
[LONG_JT_OFFDELAY]: 06
[LONG_ON_TIME_MODE]: 00
[LONG_JT_ON]: 04
[LONG_ON_TIME]: ff
[SHORT_ACTION_TYPE]: 01
[SHORT_COND_VALUE_HI]: 64
}
}
}
}

BIN
files/img_0053.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
files/img_0056.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
files/img_0105.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

BIN
files/img_0140.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

BIN
files/img_0140_small.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

BIN
files/img_0144.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

BIN
files/img_0144_small.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 KiB

BIN
files/img_0146.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

BIN
files/img_0146_small.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

BIN
files/img_0814.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

BIN
files/img_0814_small.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 928 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

BIN
files/sender_receiver.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

View File

@ -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.
<a href="https://a385e5.files.wordpress.com/2016/10/img_0053.jpg"><img src="https://a385e5.files.wordpress.com/2016/10/img_0053.jpg?w=730" alt="img_0053" width="730" height="973" class="alignnone size-large wp-image-740" /></a>
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.
<a href="https://a385e5.files.wordpress.com/2016/10/img_0054-e1476437702547.jpg"><img src="https://a385e5.files.wordpress.com/2016/10/img_0054-e1476437702547.jpg?w=730" alt="img_0054" width="730" height="548" class="alignnone size-large wp-image-741" /></a>
The bridge is a three phase IGBT module is a 6MB120F-060 I got for a few euros at ebay.
<a href="https://a385e5.files.wordpress.com/2016/10/img_0055-e1476437685461.jpg"><img src="https://a385e5.files.wordpress.com/2016/10/img_0055-e1476437685461.jpg?w=730" alt="img_0055" width="730" height="548" class="alignnone size-large wp-image-742" /></a>
To avoid high voltages in my setup I got a 24V async motor, also from ebay.
<a href="https://a385e5.files.wordpress.com/2016/10/img_0056.jpg"><img src="https://a385e5.files.wordpress.com/2016/10/img_0056.jpg?w=730" alt="img_0056" width="730" height="548" class="alignnone size-large wp-image-743" /></a>
The PWMs generate the signal from a sine table generated using Excel. Those we got this signal:
<a href="https://a385e5.files.wordpress.com/2016/10/inverter0_2016-09-23-4.png"><img src="https://a385e5.files.wordpress.com/2016/10/inverter0_2016-09-23-4.png" alt="inverter0_2016-09-23-4" width="640" height="520" class="alignnone size-full wp-image-759" /></a>
The main task of the coordinator is the start the PWMs with a phase shift of 120° (digital line 1, 2 and 3):
<a href="https://a385e5.files.wordpress.com/2016/10/2016-10-13_1.png"><img src="https://a385e5.files.wordpress.com/2016/10/2016-10-13_1.png" alt="2016-10-13_1" width="640" height="520" class="alignnone size-full wp-image-757" /></a>
Currently the PWMs start with random polarity. The interesting signals are the digital lines 4, 5 and 6.
Sometimes the motor runs:
<a href="https://a385e5.files.wordpress.com/2016/10/2016-10-13_works.png"><img src="https://a385e5.files.wordpress.com/2016/10/2016-10-13_works.png" alt="2016-10-13_works" width="640" height="520" class="alignnone size-full wp-image-753" /></a>
But sometimes not:
<a href="https://a385e5.files.wordpress.com/2016/10/2016-10-13_works_not.png"><img src="https://a385e5.files.wordpress.com/2016/10/2016-10-13_works_not.png" alt="2016-10-13_works_not" width="640" height="520" class="alignnone size-full wp-image-754" /></a>
The firmware is available on bitbucket, for the PWM controllers <a href="https://bitbucket.org/wollud1969/inverter0.git" target="_blank">here</a> and for the coordinator <a href="https://bitbucket.org/wollud1969/inverter0ctrl.git" target="_blank">here</a>.
')

View File

@ -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
<ol>
<li>Control the switches from different manufacturers with one remote.</li>
<li>Control them from really remote - from the office or from holiday.</li>
<li>Control them programmatically.</li>
</ol>
There are a couple of Arduino libraries out there which are working with this cheap 433MHz senders and receivers from China:
&nbsp;
<img class=" size-full wp-image-775 aligncenter" src="https://a385e5.files.wordpress.com/2016/11/sender_receiver.png" alt="sender_receiver" width="406" height="386" />I tried several ones, not all a really working, but finally I stopped at <a href="https://github.com/sui77/rc-switch" target="_blank">https://github.com/sui77/rc-switch</a>, which works really good.
<!--more-->
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:
<a href="https://a385e5.files.wordpress.com/2016/11/img_01012-e1478087121580.jpg"><img src="https://a385e5.files.wordpress.com/2016/11/img_01012-e1478087121580.jpg?w=730" alt="img_0101" width="730" height="548" class="alignnone size-large wp-image-791" /></a>
&nbsp;
<a href="https://a385e5.files.wordpress.com/2016/11/img_0105.jpg"><img src="https://a385e5.files.wordpress.com/2016/11/img_0105.jpg?w=730" alt="img_0105" width="730" height="548" class="alignnone size-large wp-image-784" /></a>
&nbsp;
Software for this thing can be found here <a href="https://gitlab.com/wolutator/433Receiver.git" target="_blank">https://gitlab.com/wolutator/433Receiver.git</a>.
This is how it works:
<a href="https://a385e5.files.wordpress.com/2016/11/img_0111-e1478087101747.jpg"><img src="https://a385e5.files.wordpress.com/2016/11/img_0111-e1478087101747.jpg?w=730" alt="img_0111" width="730" height="548" class="alignnone size-large wp-image-799" /></a>
&nbsp;
The second challenge is to send the codes out into air and let the power switches receive them. This is done with this thing:
<a href="https://a385e5.files.wordpress.com/2016/11/img_0100-e1478087375824.jpg"><img src="https://a385e5.files.wordpress.com/2016/11/img_0100-e1478087375824.jpg?w=730" alt="img_0100" width="730" height="548" class="alignnone size-large wp-image-803" /></a>
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.
')

View File

@ -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 <a href="https://a385e5.wordpress.com/2016/10/14/three-phase-inverter/" target="_blank">https://a385e5.wordpress.com/2016/10/14/three-phase-inverter/</a>. 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 class="alignnone size-full wp-image-815" src="https://a385e5.files.wordpress.com/2016/12/img_0140.jpg" alt="img_0140" width="3024" height="4032" />
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 class="alignnone size-full wp-image-820" src="https://a385e5.files.wordpress.com/2016/12/img_0144.jpg" alt="img_0144" width="3024" height="4032" />
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 class="alignnone size-full wp-image-825" src="https://a385e5.files.wordpress.com/2016/12/img_0146.jpg" alt="img_0146" width="4032" height="3024" />
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:
&nbsp;
&nbsp;
<a href="https://a385e5.files.wordpress.com/2016/12/img_0143-e1482141676335.jpg"><img src="https://a385e5.files.wordpress.com/2016/12/img_0143-e1482141676335.jpg?w=730" alt="img_0143" width="730" height="548" class="alignnone size-large wp-image-830" /></a>
(Some space reserved for a HMI unit to be connected via CAN ...)
')

View File

@ -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:<!--more-->
[code language="python" title="configGen.py"]
#!/usr/bin/python
from Cheetah.Template import Template
configItems = [
{&quot;label&quot;:&quot;_&quot;, &quot;key&quot;:&quot;magic&quot;, &quot;type&quot;:&quot;I&quot;, &quot;default&quot;: &quot;&quot;},
{&quot;label&quot;:&quot;Wifi SSID&quot;, &quot;key&quot;:&quot;wifiSsid&quot;, &quot;type&quot;:&quot;C&quot;, &quot;length&quot;:32, &quot;default&quot;:&quot;test&quot;},
{&quot;label&quot;:&quot;Wifi Key&quot;, &quot;key&quot;:&quot;wifiKey&quot;, &quot;type&quot;:&quot;C&quot;, &quot;length&quot;:64, &quot;default&quot;:&quot;geheim&quot;},
{&quot;label&quot;:&quot;MQTT Broker&quot;, &quot;key&quot;:&quot;mqttBroker&quot;, &quot;type&quot;:&quot;C&quot;, &quot;length&quot;:64, &quot;default&quot;:&quot;broker.hottis.de&quot;},
{&quot;label&quot;:&quot;MQTT Username&quot;, &quot;key&quot;:&quot;mqttUser&quot;, &quot;type&quot;:&quot;C&quot;, &quot;length&quot;:32, &quot;default&quot;:&quot;esp1&quot;},
{&quot;label&quot;:&quot;MQTT Password&quot;, &quot;key&quot;:&quot;mqttPass&quot;, &quot;type&quot;:&quot;C&quot;, &quot;length&quot;:32, &quot;default&quot;:&quot;geheim&quot;},
{&quot;label&quot;:&quot;MQTT ClientId&quot;, &quot;key&quot;:&quot;mqttClientId&quot;, &quot;type&quot;:&quot;C&quot;, &quot;length&quot;:32, &quot;default&quot;:&quot;changeThis&quot;},
{&quot;label&quot;:&quot;MQTT Topic&quot;, &quot;key&quot;:&quot;mqttTopic&quot;, &quot;type&quot;:&quot;C&quot;, &quot;length&quot;:64, &quot;default&quot;:&quot;IoT/espThermometer2/location/measurement&quot;},
{&quot;label&quot;:&quot;MQTT Port&quot;, &quot;key&quot;:&quot;mqttPort&quot;, &quot;type&quot;:&quot;I&quot;, &quot;default&quot;:8883},
{&quot;label&quot;:&quot;Measure Period&quot;, &quot;key&quot;:&quot;measurePeriod&quot;, &quot;type&quot;:&quot;I&quot;, &quot;default&quot;:300}
]
h_file = Template(file=&quot;configuration_h.tmpl&quot;, searchList=[{&quot;configItems&quot;:configItems}])
open('configuration.h','w').write(str(h_file))
c_file = Template(file=&quot;configuration_c.tmpl&quot;, searchList=[{&quot;configItems&quot;: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 &lt;Arduino.h&gt;
#include &lt;ESP8266WiFi.h&gt;
#include &lt;ESP8266WebServer.h&gt;
#include &lt;EEPROM.h&gt;
#include &quot;defines.h&quot;
#include &quot;configuration.h&quot;
#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 != &quot;_&quot;
#if $configItem.type == &quot;C&quot;
strcpy(configBlock.$configItem.key, &quot;$configItem.default&quot;);
#else if $configItem.type == &quot;I&quot;
configBlock.$configItem.key = $configItem.default;
#end if
#end if
#end for
}
String buffer =
&quot;&lt;!doctype html&quot;
&quot;&lt;html lang=\&quot;en\&quot;&gt;&quot;
&quot; &lt;head&gt;&quot;
&quot; &lt;title&gt;ESP8266 Thermometer Configuration Page&lt;/title&gt;&quot;
&quot; &lt;/head&gt;&quot;
&quot; &lt;body&gt;&quot;
&quot; &lt;h1&gt;ESP8266 Configuration Page&lt;/h1&gt;&quot;;
if (configSaved) {
configSaved = false;
buffer += &quot;&lt;h2&gt;Configuration saved&lt;/h2&gt;&quot;;
}
buffer +=
&quot; &lt;form action=\&quot;/config\&quot; method=\&quot;GET\&quot;&gt;&quot;
&quot; &lt;table&gt;&quot;
#for $configItem in $configItems
#if $configItem.label != &quot;_&quot;
&quot; &lt;tr&gt;&quot;
&quot; &lt;td&gt;&quot;
&quot; &lt;label for\&quot;$configItem.key\&quot;&gt;$configItem.label&lt;/label&gt;&quot;
&quot; &lt;/td&gt;&lt;td&gt;&quot;
&quot; &lt;input type=\&quot;text\&quot; name=\&quot;$configItem.key\&quot; id=\&quot;$configItem.key\&quot; &quot;;
#if $configItem.type == &quot;C&quot;
buffer += &quot; size=\&quot;$configItem.length\&quot; &quot;;
buffer += &quot; value=\&quot;&quot;;
buffer += configBlock.$configItem.key;
buffer += &quot;\&quot;&quot;;
#else if $configItem.type == &quot;I&quot;
buffer += &quot; value=\&quot;&quot;;
buffer += configBlock.$configItem.key;
buffer += &quot;\&quot;&quot;;
#end if
buffer +=
&quot; /&gt;&quot;
&quot; &lt;/td&gt;&quot;
&quot; &lt;/tr&gt;&quot;
#end if
#end for
&quot; &lt;tr&gt;&quot;
&quot; &lt;td colspan=\&quot;2\&quot;&gt;&quot;
&quot; &lt;button type=\&quot;submit\&quot;&gt;Save&lt;/button&gt;&quot;
&quot; &lt;/td&gt;&quot;
&quot; &lt;/tr&gt;&quot;
&quot; &lt;/table&gt;&quot;
&quot; &lt;/form&gt;&quot;
&quot; &lt;/body&gt;&quot;
&quot;&lt;/html&gt;&quot;;
webServer.send(200, &quot;text/html&quot;, buffer);
#ifdef DEBUG
Serial.println(&quot;indexHtml request served&quot;);
#endif
}
void configServeGetConfiguration() {
String arg;
#for $configItem in $configItems
#if $configItem.label != &quot;_&quot;
arg = webServer.arg(&quot;$configItem.key&quot;);
#if $configItem.type == &quot;C&quot;
strcpy(configBlock.$configItem.key, arg.c_str());
#else if $configItem.type == &quot;I&quot;
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(&quot;EEPROM saved&quot;);
configSaved = true;
webServer.sendHeader(&quot;Location&quot;, String(&quot;/&quot;), true);
webServer.send(302, &quot;text/plain&quot;, &quot;&quot;);
//webServer.send(200, &quot;text/html&quot;, &quot;configuration saved&quot;);
}
void showConfiguration() {
Serial.println(&quot;Configuration is&quot;);
#for $configItem in $configItems
Serial.print(&quot;$configItem.key = &quot;);
Serial.println(configBlock.$configItem.key);
#end for
Serial.println(&quot;---&quot;);
}
[/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 <code>setup()</code> and <code>loop()</code> function:
[code language="C"]
void setup() {
startTime = millis();
#ifdef DEBUG
Serial.begin(115200);
Serial.println(&quot;Starting ...&quot;);
#endif
pinMode(CONFIG_SWITCH, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
EEPROM.begin(512);
EEPROM.get(EEPROM_ADDR, configBlock);
Serial.print(&quot;Magic: &quot;);
Serial.println(configBlock.magic);
configMode = ((LOW == digitalRead(CONFIG_SWITCH)) || (configBlock.magic != MAGIC));
if (configMode) {
#ifdef DEBUG
Serial.println(&quot;Configuration mode&quot;);
#endif
digitalWrite(LED_PIN, LOW);
setupConfiguration();
} else {
#ifdef DEBUG
Serial.println(&quot;Production mode&quot;);
Serial.println();
Serial.println();
showConfiguration();
#endif
digitalWrite(LED_PIN, HIGH);
setupProduction();
}
#ifdef DEBUG
Serial.println(&quot;Started.&quot;);
#endif
}
void loop() {
if (configMode) {
loopConfiguration();
} else {
loopProduction();
}
}
void setupConfiguration() {
WiFi.mode(WIFI_AP);
WiFi.softAP(CONFIG_SSID);
#ifdef DEBUG
Serial.println(&quot;AP started&quot;);
#endif
webServer.on(&quot;/&quot;, configServeIndex);
webServer.on(&quot;/config&quot;, configServeGetConfiguration);
webServer.onNotFound(configServeNotFound);
webServer.begin();
#ifdef DEBUG
Serial.println(&quot;Webserver started&quot;);
#endif
}
void loopConfiguration() {
webServer.handleClient();
}
[/code]
This code can be also found embedded into two of my projects. Find them at <a href="https://gitlab.com/wolutator/EspThermometer2" rel="noopener" target="_blank">https://gitlab.com/wolutator/EspThermometer2</a> and <a href="https://gitlab.com/wolutator/TouchSwitch" rel="noopener" target="_blank">https://gitlab.com/wolutator/TouchSwitch</a>.
')

View File

@ -1,29 +0,0 @@
define(`TITLE', `Home Automation Hub')
define(`DATE', `2018-02-22')
define(`CONTENT', `
My home automation hub. (Photos inside)
<img class="alignnone size-full wp-image-872" src="https://a385e5.files.wordpress.com/2018/02/img_0304.jpg" alt="IMG_0304" width="4032" height="3024" />
<img class=" size-medium wp-image-873 alignleft" src="https://a385e5.files.wordpress.com/2018/02/img_0195.jpg?w=225" alt="IMG_0195" width="225" height="300" />
A Raspberry Pi runs <a href="https://homegear.eu" target="_blank" rel="noopener">Homegear</a> and <a href="https://github.com/hobbyquaker/homekit2mqtt" target="_blank" rel="noopener">homekit2mqtt</a>. It is equipped with two 866MHz radios for Homematic and MAX!.
Additionally an MQTT broker and the homegrown control software (<a href="https://gitlab.com/wolutator/dispatcher_ng" target="_blank" rel="noopener">https://gitlab.com/wolutator/dispatcher_ng</a>), which communicates with Homegear, homekit2mqtt, the MQTT433MHz bridge (see below) and other homegrown web clients via MQTT, resists on it.
<img class=" size-medium wp-image-876 alignleft" src="https://a385e5.files.wordpress.com/2018/02/img_0307.jpg?w=225" alt="IMG_0307" width="225" height="300" />
There is also a DIY MQTT to 433MHz bridge to control Intertechno and other 433MHz plugs (<a href="https://gitlab.com/wolutator/Mqtt433Gateway" target="_blank" rel="noopener">https://gitlab.com/wolutator/Mqtt433Gateway</a>).
&nbsp;
&nbsp;
&nbsp;
&nbsp;
<img class=" size-medium wp-image-881 alignleft" src="https://a385e5.files.wordpress.com/2018/02/img_0308.jpg?w=225" alt="IMG_0308" width="225" height="300" />
An finally a Philips Hue Bridge powered using a PoE adaptor for Philips and IKEA Tradfri bulbs, paired to Homegear.
')

View File

@ -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 &gt; (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:
<!--more-->
<img src="https://a385e5.files.wordpress.com/2018/04/20180430110848869_0001.jpg" alt="20180430110848869_0001.jpg" width="2332" height="3307" class="alignnone size-full wp-image-901" />
(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-&gt;buttonPin);
#ifdef DEBUG
if (button-&gt;oldPressedState != button-&gt;pressedState) {
Serial.print("Index ");
Serial.print(button-&gt;index);
Serial.print(", state changed from ");
Serial.print(button-&gt;oldPressedState);
Serial.print(" to ");
Serial.print(button-&gt;pressedState);
Serial.println();
button-&gt;oldPressedState = button-&gt;pressedState;
}
#endif
switch (button-&gt;pressedState) {
case psHIGH:
if (buttonState == LOW) {
button-&gt;pressedState = psLOW;
button-&gt;lastStateChange = currentMicros;
}
break;
case psLOW:
if (buttonState == HIGH) {
button-&gt;pressedState = psHIGH;
button-&gt;lastStateChange = currentMicros;
} else {
if (currentMicros &gt; (button-&gt;lastStateChange + configBlock.debounce)) {
button-&gt;pressedState = psACCEPTED_LOW;
button-&gt;lastStateChange = currentMicros;
}
}
break;
case psACCEPTED_LOW:
if (buttonState == HIGH) {
button-&gt;pressedState = psSHORT;
button-&gt;lastStateChange = currentMicros;
}
if (currentMicros &gt; (button-&gt;lastStateChange + (configBlock.longPress * 1000))) {
button-&gt;pressedState = psLONG_START;
button-&gt;lastStateChange = currentMicros;
}
break;
case psSHORT:
sendMsg(button-&gt;index, "PRESS_SHORT");
button-&gt;pressedState = psHIGH;
button-&gt;lastStateChange = currentMicros;
break;
case psLONG_START:
sendMsg(button-&gt;index, "PRESS_LONG_START");
button-&gt;pressedState = psLONG_CONT;
button-&gt;lastStateChange = currentMicros;
break;
case psLONG_CONT:
if (buttonState == HIGH) {
button-&gt;pressedState = psLONG_END;
button-&gt;lastStateChange = currentMicros;
}
if (currentMicros &gt; (button-&gt;lastStateChange + (configBlock.longPressRepeat * 1000))) {
button-&gt;pressedState = psLONG_CONT_SEND;
button-&gt;lastStateChange = currentMicros;
}
break;
case psLONG_CONT_SEND:
sendMsg(button-&gt;index, "PRESS_LONG_CONT");
button-&gt;pressedState = psLONG_CONT;
button-&gt;lastStateChange = currentMicros;
break;
case psLONG_END:
sendMsg(button-&gt;index, "PRESS_LONG_END");
button-&gt;pressedState = psHIGH;
button-&gt;lastStateChange = currentMicros;
break;
default:
button-&gt;pressedState = psHIGH;
button-&gt;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.
')

View File

@ -5,7 +5,7 @@ import * as cmdargs from 'command-line-args'
const OPTION_DEFINITIONS = [ const OPTION_DEFINITIONS = [
{ name: 'verbose', alias: 'v', type: Boolean }, { name: 'verbose', alias: 'v', type: Boolean },
{ name: 'config', alias: 'c', type: String, defaultValue: '~/homepage.conf' } { name: 'config', alias: 'c', type: String, defaultValue: './homepage.conf' }
]; ];

View File

@ -8,17 +8,13 @@ import * as express from 'express'
function getPageOptions(contentStr: string) : any { function getPageOptions(contentStr: string) : any {
let pageOptions : any = {} let pageOptions : any = {}
// logger.info(`contentStr: ${contentStr}`)
try { try {
let lines = contentStr.split("\n") let lines = contentStr.split("\n")
let firstLine = lines[0] let firstLine = lines[0]
// logger.info(`firstLine: ${firstLine}`)
let pageOptionsStr = firstLine.replace(/^\s*<!-- (\{.+\}) -->[\s\S]*$/, "\$1") let pageOptionsStr = firstLine.replace(/^\s*<!-- (\{.+\}) -->[\s\S]*$/, "\$1")
// logger.info(`pageOptionsStr: ${pageOptionsStr}`)
pageOptions = JSON.parse(pageOptionsStr) pageOptions = JSON.parse(pageOptionsStr)
// logger.info(JSON.stringify(pageOptions))
} catch { } catch {
// logger.info("No pageOptions found") logger.info("No pageOptions found")
} }
return pageOptions return pageOptions
} }
@ -50,6 +46,7 @@ let cache: any = {}
app.engine('pag', (filePath: string, options: any, callback: any) => { app.engine('pag', (filePath: string, options: any, callback: any) => {
// logger.info(JSON.stringify(options))
if (! (filePath in cache)) { if (! (filePath in cache)) {
logger.info(`${filePath} not yet in cache`) logger.info(`${filePath} not yet in cache`)
@ -111,7 +108,8 @@ app.get('/reload', (req, res) => {
cache = {} cache = {}
toc = getToc() toc = getToc()
masterTmpl = fs.readFileSync('./docroot/master.tmpl').toString() masterTmpl = fs.readFileSync('./docroot/master.tmpl').toString()
res.send('reload triggered') let base = req.headers['x-proxy-original-url'] || "/"
res.redirect(`${base}index`)
}) })
app.use('/files', express.static('files')) app.use('/files', express.static('files'))
@ -125,3 +123,4 @@ app.listen(config.dict.httpPort, () => {
}) })
logger.info("Homepage running") logger.info("Homepage running")