PartManager v0.1a

By | 30. November 2018

Ich war vor einiger Zeit auf der Suche nach einem schlanken Programm zur Verwaltung meiner elektronischen Bauteile. Leider waren die meisten Tools überladen und kompliziert in der Bedienung. Also entschloss ich mich, selbst eines zu schreiben. Bisher habe ich es für meine eigenen Zwecke genutzt, möchte es aber zur freien Nutzung zur Verfügung stellen und auch weiterentwickeln.

Im PartManager können Bauteile und ihre Verfügbarkeit im persönlichen “Lager” verwaltet werden. Beim Anlegen eines Datensatzes können Informationen von Conrad, Reichelt, Digikey, Pollin, Voelkner, Mouser, Watterott, Farnell, Amazon und Ebay importiert werden. Weiterhin können virtuelle Lagerkisten angelegt werden und diese mit Bauteilen gefüllt werden.

Der PartManager ist momentan noch im Alpha-Stadium und wird voraussichtlich im Frühling 2019 weiterentwickelt.

Download: PartManager

Pi Boy #2 – Display

By | 3. August 2016

parking-camera-display

Anfangs wollte ich für den Pi Boy ein SPI-Display mit 3.5″ und einer Auflösung von 320×240 Pixel einsetzten, doch leider gab es massive Probleme mit den Treibern. Also entschied ich mich für ein AV-Display aus einer Rückfahrkamera von Amazon.

Nachdem das Gehäuse geöffnet war, sprang mir direkt ein AP1509 Step Down IC ins Auge, dass die 12V Eingangsspannung auf 5V regelt. Durch Auslöten des IC und Überbrücken der Pins 1 und 2 kann das Display mit 5V direkt betrieben werden.


Weiteres folgt, sobald ich eine Lösung für das Problem mit den Tasten des Pi Boys gefunden habe.

Pi Boy #1 – Vorbereitungen

By | 20. Juli 2016

gameboy-clipart

Ich will die Zeit neben meinem Ferienjob in den Semesterferien dazu nutzen, eine Spielekonsole im Gameboy-Gehäuse zu bauen, die mit Hilfe eines Raspberry Pi und diversen Emulatoren Spiele verschiedener Konsolen starten kann.

Zuerst soll abgeschätzt werden, welcher Pi zum Einsatz kommt. Zur Auswahl stehen der Pi 3 und der Pi Zero. Die verschiedenen Emulatoren werden auf beiden Pi’s getestet:

Spiele Pi Zero Pi 3
GameBoy
GameBoy Advance
GameBoy Color
Genesis
MasterSystem
N64 ✖ (weitere Tests notwendig)
NES
PlayStation
SNES
Hardware Pi Zero Pi 3
WLAN
Audio-Buchse
Video-Buchse
USB-Anschluss ✔ (1x Micro USB) ✔ (4x USB)

Chat mit Socket.io und Node.js

By | 3. Juni 2016

Ich bin zufällig auf Socket.io gestoßen und wollte mir das Ganze direkt mal anschauen. Socket.io dient in erster Linie der schnelleren Kommunikation zwischen Server und Clients auf Basis von WebSockets.

In diesem Beitrag beschreibe ich die Installation von Socket.io und den Aufbau eines kleinen Chat-Programms auf Basis der gegebenen Demo auf der Socket.io-Website.

Installation

Zuerst wird Node.js benötigt. Es wird heruntergeladen und anschließend installiert:

curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -
sudo apt-get install -y nodejs

Weiter benötigt man das Package Build-Tools, das man ebenfalls installiert:

sudo apt-get install -y build-essential

Das Framework

Für unser Projekt erstellen wir einen neuen Ordner, z.B. “chat-example” und erstellen eine package.json

{
"name": "socket-chat",
"version": "1.0.0",
"description": "my first socket.io app",
"dependencies": {}
}

Den Chat wollen wir mithilfe des Express Frameworks erstellen, also:

npm install --save express@4.10.2

Das Server-Script

Wir erstellen eine index.js und tragen folgenden Code ein:

var app = require('express')();
var http = require('http').Server(app);

app.get('/', function(req, res){
  res.send('<h1>Hello world</h1>');
});

http.listen(3000, function(){
  console.log('listening on *:3000');
});

Der erste Schritt ist getan. Das Script kann nun mit dem Befehl node gestartet werden:

node index.js

Im Browser ist die im Programm definierte Startseite abrufbar.

Socket.io: Hallo Welt!

Der Client

Man könnte den ganzen HTML-Code per res.send() übertragen, was aber bei größeren Seiten schnell unübersichtlich wird. Wir erstellen also eine separate index.html und tragen unsere Website dort ein:

<!doctype html>
<html>
  <head>
    <title>Socket.IO chat</title>
    <style>
      * { margin: 0; padding: 0; box-sizing: border-box; }
      body { font: 13px Helvetica, Arial; }
      form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
      form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
      form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
      #messages { list-style-type: none; margin: 0; padding: 0; }
      #messages li { padding: 5px 10px; }
      #messages li:nth-child(odd) { background: #eee; }
    </style>
  </head>
  <body>
    <ul id="messages"></ul>
    <form action="">
      <input id="m" autocomplete="off" /><button>Send</button>
    </form>
  </body>
</html>

Dem Server muss mitgeteilt werden, dass er ab sofort die Website aus einer Datei lesen soll. Also ersetzen wir res.send() durch:

res.sendFile(__dirname + '/index.html');

Wir starten das Server-Script erneut und sehen, dass die index.html erfolgreich geladen wurde:

Socket.io: index.html

Kommunikation zwischen Client und Server

Es ist an der Zeit, Client und Server kommunikationsfähig zu machen. Hierbei kommt Socket.io ist Spiel, das wir jetzt installieren:

npm install --save socket.io

Fügen wir nun das Modul zur index.js hinzu:

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

app.get('/', function(req, res){
  res.sendfile('index.html');
});

io.on('connection', function(socket){
  console.log('a user connected');
});

http.listen(3000, function(){
  console.log('listening on *:3000');
});

Hier wird auf eingehende Verbindungen gewartet und jeweils eine Meldung auf der Konsole ausgegeben.
Jetzt fehlt nur noch die Anpassung in der index.html:

<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io();
</script>

Wir starten das Script neu und öffnen die Seite in mehreren Tabs. Bei jeder neuen Verbindung wird eine Meldung auf der Konsole ausgegeben.

Nicht nur eingehende, sondern auch beendete Verbindungen können mit einem Event gebunden werden:

io.on('connection', function(socket){
  console.log('a user connected');
  socket.on('disconnect', function(){
    console.log('user disconnected');
  });
});

Events abfeuern

Zur Kommunikation zwischen Client und Server werden Events abgefeuert. Daten können als Strings, JSON oder binär übertragen werden. In unserem Beispiel werden wir Strings übertragen.

Für unseren Chat brauchen wir als zuerst ein Event, dass die Nachricht an den Server schickt. Nennen wir es chat message:

<script src="/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script>
  var socket = io();
  $('form').submit(function(){
    socket.emit('chat message', $('#m').val());
    $('#m').val('');
    return false;
  });
</script>

In der index.js empfangen wir das Event:

io.on('connection', function(socket){
  socket.on('chat message', function(msg){
    console.log('message: ' + msg);
  });
});

nach einem Start der index.js werden alle Nachrichten, die über den Chat abgesendet werden, auf der Konsole ausgegeben.

Broadcasting

Der Server hat die Nachricht empfangen und muss sie jetzt an alle Clients verteilen:

io.on('connection', function(socket){
  socket.on('chat message', function(msg){
    io.emit('chat message', msg);
  });
});

Jeder Client benötigt jetzt noch einen Eventhandler:

<script>
  var socket = io();
  $('form').submit(function(){
    socket.emit('chat message', $('#m').val());
    $('#m').val('');
    return false;
  });
  socket.on('chat message', function(msg){
    $('#messages').append($('<li>').text(msg));
  });
</script>

Herzlichen Glückwunsch! Das erste Script für Socket.io ist fertig.

Ich habe mir die Mühe gemacht und noch einige Erweiterungen eingebaut:
Socket.io: Erweiterter Chat

Alle User werden jetzt auf der rechten Seite des Fensters aufgelistet. Per Klick auf einen Namen kann eine private Nachricht versendet werden. Private Nachrichten werden im Chat blau hervorgehoben. Außerdem kann man mit “/nick neuername” den aktuellen Benutzernamen ändern. Smileys werden per Klick in das Textfeld eingefügt. Zuletzt kann der gesamte Chat-Verlauf der aktuellen Session als Textdatei heruntergeladen werden.

Der Quellcode kann auf Github heruntergeladen werden: Download

Kimsufi Crawler

By | 28. Februar 2016

Kimsufi Crawler

Wenn man sich bei Kimsufi einen neuen Server zulegen möchte, ist das meist mit langen Wartezeiten verbunden. Eine hauseigene Benachrichtigung zur Verfügbarkeit wird leider nicht angeboten und die manuelle Abfrage der Seite ist unter Umständen nicht schnell genug, sodass man einen verfügbaren Server nicht bemerkt. Aus diesem Grund habe ich einen kleinen Crawler geschrieben, der in beliebigen Intervallen die Verfügbarkeit des gewünschten Servers überprüft. Ist der Server verfügbar, so öffnet sich ein Popup und der Browser öffnet direkt den Link zum Bestellformular.



package im.jahnke.kimsuficrawler;
 
import java.awt.Desktop;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URL;
import java.util.Scanner;
 
import javax.net.ssl.HttpsURLConnection;
import javax.swing.JOptionPane;
 
/**
 * KimsufiCrawler is a tool for checking the availability of Kimsufi servers 
 * 
 */
 
public class KimsufiCrawler {
     
    public static void main(String[] args) throws Exception {
         
        Scanner sc = new Scanner(System.in);
         
        System.out.println("Kimsufi Server Scanner");
        System.out.println("1 \t KS-1");
        System.out.println("2A \t KS-2A");
        System.out.println("2B \t KS-2B");
        System.out.println("2C \t KS-2C");
        System.out.println("2D \t KS-2D");
        System.out.println("3A \t KS-3A");
        System.out.println("3B \t KS-3B");
        System.out.println("3C \t KS-3C");
        System.out.println("3D \t KS-3D");
        System.out.println("4A \t KS-4A");
        System.out.println("4B \t KS-4B");
        System.out.println("4C \t KS-4C");
        System.out.println("4D \t KS-4D");
        System.out.println("5 \t KS-5");
        System.out.print("Choose Server: ");
        
        String chosenServer = "";
        switch (sc.nextLine()) {
        case "1":
            chosenServer = "160sk1";
            break;
        case "2A":
            chosenServer = "160sk2";
            break;
        case "2B":
            chosenServer = "160sk21";
            break;
        case "2C":
            chosenServer = "160sk22";
            break;
        case "2D":
            chosenServer = "160sk23";
            break;
        case "3A":
            chosenServer = "160sk3";
            break;
        case "3B":
            chosenServer = "160sk31";
            break;
        case "3C":
            chosenServer = "160sk32";
            break;
        case "3D":
            chosenServer = "160sk33";
            break;
        case "4A":
            chosenServer = "160sk4";
            break;
        case "4B":
            chosenServer = "160sk41";
            break;
        case "4C":
            chosenServer = "160sk42";
            break;
        case "4D":
            chosenServer = "160sk43";
            break;
        case "5":
            chosenServer = "160sk5";
            break;
        default:
            chosenServer = "";
            break;
        }
         
        System.out.print("Sleeping time in seconds: ");
        int sleepingTime = sc.nextInt()*1000;
         
        sc.close();
         
        while(true){
            System.out.println("Scanning for available server...");
            String pageContent = getPageContent("https://www.kimsufi.com/en/order/kimsufi.cgi?hard=" + chosenServer + "&dedicatedQuantity=1");
            if(!pageContent.contains("invalide") && !pageContent.contains("rapprovisionnement")){                
                Desktop.getDesktop().browse(new URI("https://www.kimsufi.com/en/order/kimsufi.cgi?hard=" + chosenServer + "&dedicatedQuantity=1"));
                JOptionPane.showMessageDialog(null, "Alarm");
                return;
            } else {
                System.out.println("No free servers found...");
            }
             
            Thread.sleep(sleepingTime);
            System.gc();
        }
    }
     
    private static String getPageContent(String url) throws Exception {
 
        String inputLine;
        StringBuffer response = new StringBuffer();
         
        URL obj = new URL(url);
        HttpsURLConnection conn = (HttpsURLConnection) obj.openConnection();
 
        conn.setRequestMethod("GET");
 
        conn.setUseCaches(false);
 
        conn.setRequestProperty("User-Agent", "Mozilla/2.0");
        conn.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
        conn.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
         
        try {
            BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
             
 
            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine);
            }
            in.close();
            conn.disconnect();
            conn = null;
        } catch (Exception e) {
            response.append("invalide");
        }
 
        return response.toString();
 
    }
 
}


Das Git-Repository kann hier verfolgt werden: Link

CH340G Treiber für Arduino

By | 24. Februar 2016

Arduino Uno R3 Clone mit CH340G

Viele Arduino Clones aus China verwenden statt dem Atmega16U2 den günstigeren CH340G. Dieser benötigt einen speziellen Treiber, der leider nicht leicht zu finden und oft nur auf chinesischen Seiten verfügbar ist, dessen Seriösität nicht immer bewertet werden kann.

Download
CH340G Treiber | 135 kB

DS3231M I2C Library Arduino

By | 5. Februar 2016

Da es leider keine Bibliothek für den DS3231M gab, die meinen Anforderungen entspricht, habe ich eine eigene entwickelt. Folgende Funktionen sind vorhanden:

  • Zeit setzen
  • Zeit auslesen
  • Temperatur auslesen
  • Mehrere Module durch freie Adresswahl an einem Bus betreiben
Methodenübersicht Anzeigen
#include <RTC.h> //RTC library

void setup() {
  Serial.begin(250000);
  RTC.setSeconds(30);
  RTC.setMinutes(7);
  RTC.setHours(12);
  RTC.setDay(5);
  RTC.setMonth(2);
  RTC.setYear(16);
}

void loop() {
  Serial.print(RTC.getDay());
  Serial.print(".");
  Serial.print(RTC.getMonth());
  Serial.print(".");
  Serial.print(RTC.getYear());
  Serial.print(" ");
  Serial.print(RTC.getHours());
  Serial.print(":");
  Serial.print(RTC.getMinutes());
  Serial.print(":");
  Serial.print(RTC.getSeconds());
  Serial.print(" Temperature: ");
  Serial.println(RTC.getTemperature());
  delay(100);
}

Downloads:

Download
DS3231M Datenblatt | 891 kB

Download
RTCLib | 2 kB

Project Euler: Problem 23

By | 4. Oktober 2015

A perfect number is a number for which the sum of its proper divisors is exactly equal to the number. For example, the sum of the proper divisors of 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28 is a perfect number.

A number n is called deficient if the sum of its proper divisors is less than n and it is called abundant if this sum exceeds n.

As 12 is the smallest abundant number, 1 + 2 + 3 + 4 + 6 = 16, the smallest number that can be written as the sum of two abundant numbers is 24. By mathematical analysis, it can be shown that all integers greater than 28123 can be written as the sum of two abundant numbers. However, this upper limit cannot be reduced any further by analysis even though it is known that the greatest number that cannot be expressed as the sum of two abundant numbers is less than this limit.

Find the sum of all the positive integers which cannot be written as the sum of two abundant numbers.

public class Problem23 {

	static List<Integer> abundant = new ArrayList<Integer>();
	static Set<Integer> sumList = new HashSet<Integer>();


	static long sum = 0;

	public static void main(String[] args) {
		for (int i = 1; i <= 28123; i++) {
			if (getSumOfDivisors(i) > i) {
				abundant.add(i);
			}
		}
		System.out.println("Total abundant numbers: " + abundant.size());
		for (int j = 0; j < abundant.size(); j++) {
			for (int k = 0; k < abundant.size(); k++) {
				int tempNum;
				if ((tempNum = abundant.get(j) + abundant.get(k)) < 28123) {
					sumList.add(tempNum);
				}
			}
		}
		System.out.println("Sum list generated: " + sumList.size());
		for (int i = 0; i < 28123; i++) {
			if (!sumList.contains(i)) {
				sum += i;
			}
		}
		System.out.println(sum);

	}

	public static int getSumOfDivisors(int number) {
		int sum = 0;
		for (int j = number / 2; j > 0; j--) {
			if (number % j == 0) {
				sum += j;
			}
		}
		return sum;
	}

}

Lösung: 4179871