Arduino controlled Tomato, Chard and Zucchini watering for the balcony

Tomate1 Tomaten Mangold BewaesserungDropsArduino

Purpose

Watering my balcony so I have fresh tomatoes every morning for breakfast, plus some zucchini and chard for dinner every week without having to take care about the plants every day. Survival of my plants during my vacations. I do have a power supply on the balcony, but the setup should just use 12v so i can run it on a used car battery later.

It should actively pump water, I do not have a water tap on the balcony and it should work “out in the wild” as well. Failsafe – shouldn’t die if it runs dry.

Components

External 5.25” HDD housing with 12v power supply (From an old, defect hard drive)

Arduino Leonardo

HC Thor Fahrtregler (Fahrtregler)

(I use this one because I want to be able to use the System with a much larger fuel pump later as well)

RC Fuel Pump with 5v Motor e.g. (Zahnradpumpe)

(The fuel pump works perfect, but it quite noisy. Thus, i have replaced it with Tauchpumpe but be aware this one dies if it runs dry. The current code uses the moisture sensor under water to check if there is enough water in the supply. With the fuel pump, all of my neighbours asked me what that strange noise from my balcony is and speculated wildly – but no one was angry, it’s not that loud after all…)

If you connect the fuel pump, you have to heat the micro-drip cable with a lighter close to the end and then pull the end carefully to reduce the diameter. Cut at the minimum diameter so that it fits tightly on the pump pressurized exit.

For the Tauchpumpe, use some shrink tubing that just fits around the pump exit, insert the micro drip cable a centimeter into the pump and heat the shrink tube to firmly connect the components.

Micro Drip System (Micro Drip ) plus one row of cable.

One M-Ohm Resistor

Setup

  • Mount Arduino to hard drive housing (Screws/Plastic/…)
  • Program Arduino
  • Connect “Fahrtregler” with yellow and blue line to fuel pump, red and black to 12v power from the HDD power supply. Small brown control is GND on arduino, orange control line goes to a control pin, i used 9. The small red line is the receiver power line, leave it open, we don’t need it.
  • Connect arduino external power to 12v, and ground to HDD ground.
  • I have added a moisture measurement. Three wires, ground, plus, measure. Wiring plus -> 1MOhm resistor -> measurement cable and moisture detector-> Minus. For a moisture detector, you can use e.g two screws connected to wires and spaced by a dowel (just cut the closed end open and add the second screw from there). The screws should have a little space in between. Bury this. If the space in between filled by earth gets wet – lower resistance. Of course this is temperature dependant…. but it works fine for me without temperature compensation.
  • I connected the HDD diodes to display status information.

Code

The current code just runs watering every minute, hour or two hours if the earth is too dry.

Best results for my tomatoes : Run the watering every hour and keep them constantly moist.

Use fresh tomato earth. If the tomatoes don’t grow steady – check for small animals. If none, add some fertilizer. If they still don’t grow fast – move to a more sunny location or do the sundance (Sundance).

// Bewaesserungsprogramm
// Wolfram Teetz <wolframteetz@gmail.com>

#include <Servo.h>

Servo MotorServo; // Liquid Motor servo object to control a servo

int x = 0; // counter for delays between single motor activations
int startval = 250;

long count; // 1/10s of seconds the ardu is running

long onTime1;
long offTime1;

long onTime2;
long offTime2;

int potpin = 0; // analog pin used to connect the potentiometer
int val; // variable to read the value from the analog pin

void cdelay(int d) // counting delay
{
count += d/100;
count %= 24*36000L;
delay(d);
}

boolean testTime() // test of we’re active at this time
{
// Assume watering starts in the evening
if ((digitalRead(1)==LOW)&&(count>=onTime1)&&(count<offTime1)) return true; // Pin 1 closed = water evening
if ((digitalRead(1)==LOW)&&(count>=onTime2)&&(count<offTime2)) return true; // Pin 1 closed = water morning
if (digitalRead(2)==LOW) return true; // Pin 2/3 closed = always water
if (digitalRead(3)==LOW) return true; // Pin 2/3 closed = always water
return false;
}

void setup()
{
//Serial.begin(9600); // S E R I A L
MotorServo.attach(9); // attaches the servo on pin 9 to the servo object
MotorServo.write(90); // sets the servo position according to (value between 0 and 180)
cdelay(50); // waits for the servo to get there
x = 0;
count = 0L; // in 1/10 of seconds

onTime1 = 0L; // start immediate (8PM)
offTime1 = 5L*3600L; // +0.5h (9PM)

onTime2 = 130L*3600L; // +13.0h (9AM)
offTime2 = 135L*3600L; // +13.5h (10AM)

// Control pins
// For meaning, see testTime function
pinMode(0, OUTPUT); // sets the digital pin 13 as output
digitalWrite(0, LOW);
for (int i=1; i<=3; i++) {
pinMode(i, INPUT);
pinMode(i, INPUT_PULLUP);
}

// LED’s
for (int i=4; i<=7; i++) {
pinMode(i, OUTPUT);
}
digitalWrite(5, LOW); // Led mass
digitalWrite(6, LOW); // Led mass

pinMode(11, OUTPUT); // sets voltage on pin 11 as input to measureing moisture
digitalWrite(11, HIGH); // input on analogue pin 0
}

void loop()
{
// Serial.println(val);
// Offen : 1023
// Relativ trockene Erde : 520
// Feuchte Erde : 250
// Pitschnass : 100
// Unter Wasser : 60

// Serial.print(“LOOP “); // S E R I A L

if (x<=0) {

//val = map(val, 0, 1023, 0, 179); // scale it to use it with the servo (value between 0 and 180)
val = analogRead(potpin); // 0–1000 -> SHOW : 0 to 20 CLICKS – 20 is DRY, 0 is WET. 10 Starts watering by default.

// Show value
int highval = val;
if (startval>val) highval=startval;

for (int vx=0; vx<highval; vx++)
{
if ((vx%2)==0) {
digitalWrite(4,LOW);
digitalWrite(7,LOW);
} else {
if (vx < startval) digitalWrite(4, HIGH);
else digitalWrite(4, LOW);
if (vx < val) digitalWrite(7, HIGH);
else digitalWrite(7, LOW);
}
delay(5);
}

digitalWrite(4,LOW);
digitalWrite(7,LOW);
if (x==0) delay(1000);

// There is water in the bucket
if (val<startval) {
digitalWrite(7, HIGH); // “currently watering” diode on
digitalWrite(4, LOW);
for (int vx=0; vx<44; vx++) // Slowly start
{
MotorServo.write(90+vx);
cdelay(100); // one step each 0.1 seconds
}
MotorServo.write(90+44); // run at ca. 6V, 12V supply
cdelay(30000); // run for 30 seconds
MotorServo.write(90); // turn off
cdelay(100);
digitalWrite(7, LOW); // “currently watering” diode off
digitalWrite(4, LOW);
x=10*60; // default
if (digitalRead(3)==LOW) x = -1; // constant watering
if (digitalRead(2)==LOW) x = 30*60; // one trigger per 30m
if (digitalRead(1)==LOW) x = 60*60; // one trigger per 1h
} else { // Of val>startval, Means there is no water in the bucket
x=10*60; // default
if (digitalRead(3)==LOW) x = -1; // constant watering
if (digitalRead(2)==LOW) x = 30*60; // one trigger per 30m
if (digitalRead(1)==LOW) x = 60*60; // one trigger per 1h
} // else of val>startval

} // if x==0 (active interval, not sleep interval)

if (x>0) { // sleep interval, count down
x = x – 1;
}

// Wait
cdelay(1000);

}

Typesetting Guitar Tabs

Screen Shot 2015-03-25 at 15.59.17

Windsurfing and guitar playing go well together. So you might think. But in reality, even if there is “no wind” for windsufers, there is still “hell lot of wind” for guitar players on the beach – after all, you went to the windiest spot you could find to surf. So I’m constantly struggeling with “flying pages” when I try to learn a new song on the beach. In addition, everything gets wet all the time…

Something that helps pretty well is laminating the song pages. Since laminating a lot of songs is quite some work – I’d like to laminate as few pages as possible. This is a good idea anyway, since it’s also great to have songs on one page not having to swap pages while playing— although I’d keep a backup of a few multi-page songs in case you want to ask some girl to sit next to you and switch then for you.

Getting songs on one page and highlighting the chords (really helps when the wind moves the paper, right chord, sing lala, everything’s fine..) is quite some work. Thus, is started working on a

Script that typesets guitar chords, e.g. those you can grab from ultimate guitar – from text to a one-page PDF.

Example:

Screen Shot 2015-03-25 at 16.06.35

becomes

Screen Shot 2015-03-25 at 16.07.04

and everything should be nicely fitted in multiple columns on one page.

This is work in progress, feel free to add your improvements… works on my Mac, should work on all *nix systems…

Usage

install wkhtmltopdf

Copy and paste text from e.g. ultimate guitar to a text file, e.g. test.txt, then run makeChords.sh test.txt and open the resulting test.txt.pdf

makeChods.sh

lex lex_head.l
gcc -ll lex.yy.c
mv a.out head.out
lex lex.l
gcc -ll lex.yy.c
mv a.out main.out
./head.out $1 > head.html
./main.out $1 > main.html
sed -n ‘1,61p’ main.html > firstpage.html
sed -n ‘62,122p’ main.html > secondpage.html
cat test_head.html head.html firstpage.html test_middle.html secondpage.html test_tail.html > test_cat.html
wkhtmltopdf -O Landscape test_cat.html $1.pdf
#open $1.pdf

lex_head.l

/* scanner for chords head */

%{
typedef int bool;
#define true 1
#define false 0
bool word;
%}

DIGIT    [0-9]
NOTE     [CDEFGAHBcdefgahb]m?
CHORD    {NOTE}{DIGIT}
WORD     [a-zA-Z0-9]+
TAB      [\t]
SPACE    [ ]
NEWLINES [\n]+

%%

{CHORD}       printf(“<chord>%s</chord>”, yytext );
{WORD}        { printf(“<b>%s</b>”, yytext ); word=true; }
{SPACE}       printf(” “);
{TAB}         printf(“\t”);
{NEWLINES}    { if (word) { printf(“<br>”); return 0; } }
.             // eat

%%

int main( int argc, char **argv )
{
++argv, –argc;  /* skip over program name */
if ( argc > 0 )
yyin = fopen( argv[0], “r” );
else
yyin = stdin;

return yylex();
}

lex.l

/* music chord file scanner */

%{
#include <string.h>
typedef int bool;
int chordline = 0;
int spacesInLine = 0;
int lineContent = 0;
int wordline = 0;
int resultLinePosition=0;
int lineLength=50;
char overlength[1024];
char buffer[1024];
%}

DIGIT    [0-9]
NOTE     [CDEFGAHBcdefgahb]
CHORD    {NOTE}\/?#?b?{DIGIT}?m?{SPACE}?
WORD     [a-zA-Z0-9’\(\)]+
TAB      [\t]
SPACE    [ ]
NEWLINES [\n]+

%%

{SPACE}     { spacesInLine++; //resultLinePosition++;
if (resultLinePosition<lineLength)
{
printf(” “);
} else {
if (resultLinePosition>lineLength)
{
strcat(overlength,” “);
} else {
spacesInLine–; resultLinePosition–; // ignore these space “right in the end of the line wrap”
}
}
}

{CHORD}     {
if (wordline==0) {
lineContent++; chordline = 2;
while (spacesInLine–>0) {
resultLinePosition++;
if (resultLinePosition<lineLength) {
printf(“&nbsp;”);
} else {
strcat(overlength, “&nbsp;”); // store chord in overlength and add later
}
}
resultLinePosition += strlen(yytext);
if (resultLinePosition<lineLength) {
printf(“<chord>%s</chord>”, yytext );
} else {
sprintf(buffer, “<chord>%s</chord>”, yytext );
strcat(overlength, buffer);
}
} else { // Chord in a wordLine. just print it. THIS NEEDS PROPER WRAPPING!
if (chordline>0)printf(“%s”,yytext);
}
}

{WORD}      {
if (chordline != 2) wordline = 1;
lineContent++;
if (chordline==2) {
while (spacesInLine–>0) {
resultLinePosition++;
if (resultLinePosition<lineLength) {
printf(“&nbsp;”);
} else {
strcat(overlength, “&nbsp;”); // store chord in overlength and add later
}
}
resultLinePosition += strlen(yytext);
if (resultLinePosition<lineLength) {
printf(“%s”, yytext );
} else {
sprintf(buffer, “%s”, yytext );
strcat(overlength, buffer);
}
}
if (chordline==1) {
while (spacesInLine–>0) {
resultLinePosition++;
if (resultLinePosition!=lineLength) {
printf(“&nbsp;”);
} else {
printf(“\n<br>”);
printf(“%s”,overlength); printf(“<br>”);
printf(“&nbsp;”);
}
}
resultLinePosition += strlen(yytext);
if (resultLinePosition<lineLength) {
printf(“%s”, yytext );
} else {
if (resultLinePosition-strlen(yytext)>=lineLength) { // was wrapped already
printf(“%s”, yytext );
} else {
printf(“\n<br>”);
printf(“%s”,overlength); printf(“<br>”); // wrap now
printf(“%s”, yytext );
}
}
}
}

{TAB}       {
spacesInLine += 4;
if (chordline>0) {
resultLinePosition += 4;
printf(”    “);
}
}

{NEWLINES}  {
if (lineContent>0) {
wordline=0; chordline–; lineContent=0; spacesInLine=0;
if (chordline>=0) { // Return in chordline or line-after-chordline
printf(“\n<br>”);
if ((chordline==0) && strlen(overlength)>0) {
printf(“%s”,overlength); // flush overlength there are chords without text in OL
printf(“\n<br>”);
overlength[0]=0; // reset overlength string
}
}
resultLinePosition=0;
}
}

.

%%

int main( int argc, char **argv ) {
++argv, –argc;  /* skip over program name */
overlength[0]=0;
wordline=0;
if ( argc > 0 ) {
yyin = fopen( argv[0], “r” );
} else {
yyin = stdin;
}
return yylex();
}

test_head.html

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01//EN”
http://www.w3.org/TR/html4/strict.dtd”&gt;
<html>
<head>
<title>Zweispaltiges Layout – Struktur</title>

<style type=”text/css”>
#wrap {
width:1200px;
margin:0 auto;
}
#left_col {
font-family:monospace;
float:left;
width:600px;
}
#right_col {
font-family:monospace;
float:right;
width:600px;
}
chord {
color: red;
}
</style>

</head>
<body>

<div id=”wrap”>
<div id=”left_col”>

test_middle.html

    </div>
<div id=”right_col”>

test_tail.html

    </div>
</div>

</body>
</html>

iDotsBot

iDotsBot is a simple Java application that plays Dots on your mobile phone for you in “Turns” mode.

What you see is what you get (there’s no user interaction at all,the java app is doing all that’s happening)

In its current form it does not use the powerups since i enjoy having a little extra credits from running the bot. But using powerups is very easy to implement after all, so if you want it, feel free to add them. It will reload the board until in finds a reasonably good starting szenario and will often deliver more than 300 points without powerups. Add some extra moves and you easily reach 400+.

I wanted to compare several strategies (like this one) to play Dots and especially test a ruleset generator on the game and check how well other people’s strategies work out. Since I’m too lazy too do that manually, I’ve decided to code an automatic system to do exactly that.

You can check out the source code here : https://github.com/wolframteetz/java/tree/master/iDotsBot

If somebody’s interested, i can also create an app from it an upload it to MacUpdate once it’s mature enough ;)

The bot captures the screen of my mac (or your java machine) and uses simulated mouse clicks on the UI to interact with dots. I like, recommend and use TeamViewer to bridge my computer to my phone. Check it out, it’s free for personal use and a great piece of software.

If you’re a developer and you’d like to contribute

The DotFigures class needs to be refactored and added. It basically plays like a human, it searches for “patterns” like “burgers” or “quads”, ranks them and executes on them. I think I’ll add a “virtual score” for them and integrate them with the normal depth first search if I find some time to do that.

Monitoring your internet connection

Half a year ago my DSL Connection started dropping every hour or so and is re-established after a minute. This was very annoying.

Since O2 ships this blautiful router which gives no information at all, how to document these connection losses?

What I have so far:

checkinternet.sh (shell script)

#!/bin/bash
echo "Date - Localhost - o2.box - LAN Printer - Spiegel.de" > checkinternet.log
while true
date >> checkinternet.log
do
( while read ip; do ping -c1 -W1 -q $ip; done ) < ips | grep round >> checkinternet.log
sleep 10
done

ips (text file)

localhost
o2.box
192.168.1.2
www.spiegel.de

checkinternet.l (lex script)

%{
#include <stdio.h>
%}
%%
[a-zA-Z]+[ ][a-zA-Z]+[ ][0-9]+[ ]     printf("\n"); /* printf("\n%s,", yytext); */
[0-9]+[\:][0-9]+[\:][0-9]+            printf("%s,", yytext);
CEST      /* ignore */
\n        /* ignore */
[ \t]     /* ignore */
round-trip /* ignore */
min      /* ignore */
avg      /* ignore */
max      /* ignore */
stddev      /* printf("CONNECT "); */
=        /* ignore */
[0-9]+\.[0-9]+                       printf("%s,", yytext);
\/       /* ignore */
ms      /* ignore */
[0-9]+ /* ignore year */
%%

Compile with

lex checkinternet.l
cc lex.yy.c -o checkinternet -ll

Then run checkinternet.sh for a few hours, then

./checkinternet < checkinternet.log > checkinternet.csv
tail checkinternet.csv
open /Applications/Microsoft\ Office\ 2011/Microsoft\ Excel.app/ checkinternet.csv

And plot rows 1,5,… screenshot and annotate with the Mac OS Preview

Works – but there is room for improvement. Comments are always welcome.

Snake Cube Puzzle Solver

DSCN3573

In Octave / Matlab

I got this 4×4 “maximum” difficulty snake cube for christmas (with the solution removed from the package of course…) and decided it would be much faster to solve it by programming it than by hand…

So, if you’re searching for a solution, here is a general one

You will need GNU Octave, you can install it on OSX by running brew install octave assuming you have homebrew installed. For Windows, just follow the link above.

Run by creating the two files below in your favourite text editor, modify the Snake Vector S, start vector P and starting direction v to match your snake, run octave, start RunSnake

Script (RunSnake.m), edit your Cube here

# Octave Snake Code
# 31.12.2014 - 1.1.2015, Wolfram Teetz <wolframteetz@gmail.com>

global iter;
global maxdepth;
global maxmatrix;
global nulltime;
global lasttime;

iter = 0;         % Iteration
maxdepth = 0;     % Maximum solved depth so far
maxmatrix = 0;    % Best solution so far
nulltime=0;       % Start time in seconds
lasttime=0;       % Start time of last iteration in seconds

S = [4 2 4 2 2 2 2 3 2 2 2 2 2 3 2 4 2 3 3 4 2 3 2 2 2 2 2 2 2 2 2 4 2 4 2 4 4 4 3]; % My snake - length of all edges
S = fliplr(S);    % Solve backwards (optional)
W = zeros(4,4,4); % Cube volume
v = +1;           % Starting direction +1=Ascending in dimension 1 == x, -2 would be descending in y etc.
p = [2 1 1];      % Starting position x=2, y=1, z=1
nr = 1;           % Start with stone #1

disp ('Starting Search...');
fflush(stdout);
nulltime = time;
r=OctaveSnake(S,W,v,p,nr,false);
fflush(stdout);

The recusive main function (OctaveSnake.m)

function r = OctaveSnake(xS, xW, xv, xp, xnr, dispy)

    global iter;
    global maxdepth;
    global maxmatrix;
    global nulltime;
    global lasttime;

    iter = iter + 1;
    if (mod(iter,10000) == 0)
        clc
        disp("Iteration ");
        disp(iter);
        disp("Time");
        disp((time-lasttime));
        lasttime=time;
        disp("Total Time");
        disp((time-nulltime));
        disp("Maxdepth ");
        disp(maxdepth);
        disp("Max Matrix");
        disp(maxmatrix);
        fflush(stdout);
    endif

    if (dispy) disp("Try to continue from position"); endif;
    if (dispy) disp(xp); endif;
    if (dispy) disp("Direction"); endif;
    if (dispy) disp(xv); endif;

    for (i=2:xS(1))

        % Check state
        if (min(xp)<1)
            r = false;
            if (dispy) disp("  out of 4x4 -- abort"); endif;
            return;
            % out of bounds
        endif
        if (dispy) disp("  minok"); endif;

        if (max(xp)>4)
            r = false;
            if (dispy) disp("  out of 4x4 -- abort"); endif;
            return;
            % out of bounds
        endif
        if (dispy) disp("  maxok"); endif;

        if (xW(xp(1),xp(2),xp(3))!=0)
            r = false;
            if (dispy) disp("  collision -- abort"); endif;
            return;
            % collision, stone at this position already
        endif
        if (dispy) disp("  no collision"); endif;

        % Test, if there are enough free complete rows of 4 stones empty for remaining 4-rows
        if (i==2) % Only on the first iteration per call
            cremaining = length(find(xS==4));
            cfree = sum(sum( (sum(xW, 1)==0) ));
            cfree += sum(sum( (sum(xW, 2)==0) ));
            cfree += sum(sum( (sum(xW, 3)==0) ));
            if (cremaining>cfree)
                r = false;
                return;
            endif
        endif

        if (dispy) disp("  place length"); endif;
        if (dispy) disp(xS(1)); endif;

        if (dispy) disp("Set Stone #"); endif;
        if (dispy) disp(xnr); endif;

        xW(xp(1),xp(2),xp(3))=xnr; %  Set stone, prepare next stone
         % xW(xp) = xnr; % Keep in mind this gives an error in Octave

        xnr = xnr + 1;
        xp(abs(xv)) += sign(xv);

        if (dispy) disp("New Position"); endif;
        if (dispy) disp(xp); endif;

        % New maximum depth found
        if (xnr>maxdepth)
            maxdepth = xnr;
            maxmatrix = xW;
        endif

        if (xnr>63)
            disp("S O L U T I O N");
            disp("---------------");
            disp(xW); % Display state
            r = true;
            fflush(stdout);
            pause;
            return;
        endif

        % Move one field
    endfor

    for (nV=[-3 -2 -1 1 2 3])
        if (abs(nV) != abs(xv)) % Orthogonal turn
            r = OctaveSnake(xS(2:length(xS)), xW, nV, xp, xnr,dispy); % Turn and enter recursion
            if (r) return; endif;
        endif
    endfor

endfunction

Your solution will be displayed like this :

S O L U T I O N
—————
ans(:,:,1) =

12   11   10    9
  24   25    8
2   27   26    7
3    4    5    6

ans(:,:,2) =

13   22   31   32
14   23   30   33
15   28   29   34
16   37   36   35

ans(:,:,3) =

20   21   50   51
19   48   49   52
18   47   54   53
17   38   55   56

ans(:,:,4) =

43   44   61   60
42   45   62   59
41   46   63   58
40   39    0   57

Meaning you should put the first stone (1) on the lowest level (:,:,1), stone 2 below, stone 3 below, stone 4 to the right, … , stone 12 to the left, stone 13 above #12, then 14 below 13 and so on…

Image

iMango 1.2 for Mac OS X

ScreenShotAll

Click on the image to download the current version 1.2

iMango is a supplement of Spotlight. It finds files, folders or contents in any file and diplays the results in a tree view, so that you can browse through the folder structure of the results much quicker and more intuitively than in Spotlight.

It is donationware and you can freely download it here fully functional.

Drag files onto the window (e.g. one word file from your Desktop) to quickly get an overview which subfolders of your desktop contain word files. If you can find some similar files, try selecting 2 or more of them at once and dragging them onto iMango together. iMango will search the files that contain the largest common substring – e.g. for “Annual marketing report 2013.docx” and “Annual business report 2013.xlsx” it will search all files containing “report 2013.” automatically.

Finding your files real easy.

Version 1.2 is compatible with Mavericks. Confirmed to work on 10.6 – 10.9 and should work on 10.5

System requirements : Mac OS X

Windows and linux versions on request