Raspberry Pi

LedMatrix

Noch so ein Projekt was gefühlt schon ewig (zwei Jahre) zurückliegt, aber ich noch keine Zeit gefunden habe darüber zu schreiben. Eigentlich seit ich etwas mit Computer mache, wollte ich mir schon immer eine LED Matrix bauen.

 

Mir macht Löten keinen Spaß, darum hab ich das immer gescheut. Aber mit LED-Stripes ist das nun einfach und sogar relativ günstig. Man braucht eigentlich nur folgendes:

  • LED-Stripes: 16×16=256 (hab WS2812b genommen, sind nur 3-Leiter)
  • Netzteil: In meinem Fall 20A
  • Mikrocontroller: Muss schnell genug sein. Hab nen Tensy genommen
  • Optional Rapsberry Pi: Damit kann ich Ihn vom Netzwerk aus steuern
  • Optional USB-Umschalter: Damit kann ich zwischen Raspberry Pi und Standalone umschalten

Nun hab ich mir eine MDF-Platte hergeschnitten und Fächer aus Kunststoff erstellt. Hier wenn möglich was leichteres nehmen. Die LED-Matrix ist sehr schwer geworden. Hatte noch bisl Holz rumliegen. Das hab ich geflämmt. Milch-Plexiglas hab ich fertig bestellt.

Den Tensy kann man mit Arduino programmieren. In meinem Fall läuft ne Laufschrift durch bis ein Signal von Serial kommt. Hier nutze ich auf dem Pi Glediator. Über Screens kann ich vom iPad aus auch auf den Pi per VNC und das bequem bedienen (oder per Handy was auf einer Party praktisch ist).

#include <FastLED.h>
#include <LEDMatrix.h>
#include <LEDText.h>
#include <Font12x16.h>

#define LED_PIN            4

#define COLOR_ORDER         GRB
#define CHIPSET             WS2812B

// initial matrix layout (to get led strip index by x/y)
#define MATRIX_WIDTH   16
#define MATRIX_HEIGHT  16
#define MATRIX_TYPE    HORIZONTAL_ZIGZAG_MATRIX
#define MATRIX_SIZE    (MATRIX_WIDTH*MATRIX_HEIGHT)
#define NUMPIXELS      MATRIX_SIZE

#define WAITMAX      100000

// create our matrix based on matrix definition
cLEDMatrix<MATRIX_WIDTH, MATRIX_HEIGHT, MATRIX_TYPE> leds;
cLEDText ScrollingMsg;

int waitCount = 0;


const unsigned char TxtDemo[] = { EFFECT_SCROLL_LEFT " Hello World "};

void setup()
{
  Serial.write("Setup...\n");
  

  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);

  FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds[0], leds.Size());
  FastLED.setBrightness(255);
  FastLED.clear(true);
  FastLED.show();   
     
  FastLED.showColor(CRGB::Red);  
  delay(500);
  
  FastLED.showColor(CRGB::Green);  
  delay(500);
  
  FastLED.showColor(CRGB::Blue);
  delay(500);

  ScrollingMsg.SetFont(Font12x16Data);
  ScrollingMsg.Init(&leds, leds.Width(), ScrollingMsg.FontHeight(), 0, 0);
  ScrollingMsg.SetText((unsigned char *)TxtDemo, sizeof(TxtDemo) - 1);
  ScrollingMsg.SetTextColrOptions(COLR_RGB | COLR_SINGLE, 0xff, 0x00, 0xff);  
  
}

int serialReadBlocking() {
while (!Serial.available()) {}
    return Serial.read(); 
}

void loop()
{
  if (Serial.available())
  {
    waitCount = 0;
    while (serialReadBlocking() != 1) {} 
    digitalWrite(13, HIGH);
    for (long i=0; i < MATRIX_SIZE; i++) {
      leds(i).r = serialReadBlocking();
      leds(i).g = serialReadBlocking();
      leds(i).b = serialReadBlocking();
    }
    FastLED.show(); 
    digitalWrite(13, LOW);
  }
  else
  {    
    waitCount++;
    if(waitCount > WAITMAX)
    {
      waitCount = WAITMAX; // Fix no overflow
      if (ScrollingMsg.UpdateText() == -1)
      {
        digitalWrite(13, HIGH);      
        ScrollingMsg.SetText((unsigned char *)TxtDemo, sizeof(TxtDemo) - 1);          
      }
      else
      {      
        FastLED.show();      
        digitalWrite(13, LOW);
      }
      delay(50);
    }    
  }  
}

Für die Elektronik hab ich (verzeiht es mir) PE-Brücken genommen und dort immer die Spannungsversorgung der Stripes parallel drauf geschalten. Das Signal vom Tensy muss aber durchgeschleift werden.

Machte echt Spaß und sieht super aus!

Von |2018-07-26T06:00:07+02:002018-07-25|Projekte, Raspberry Pi|

Raspberry Pi Namen setzen

Ich schreib das hier auch mal auf, da ich selbst immer danach suchen muss :^)

Man muss an verschiedenen Stellen den Namen des Pis eingeben, damit dieser auch überall angezeigt wird:

sudo nano /etc/hosts
sudo nano /etc/hostname
sudo /etc/init.d/hostname.sh

Nach einem Neustart hat das Kind einen Namen.

 

Update

Danke an Hermann für den Hinweis… es ist (nun) möglich auch per raspi-config  den hostnamen zu setzen. Das Feature kam irgendwann hinzu… ich werde alt…

Die Lösung oben kann auch jeder Linux Distri benutzt werden :^)

Von |2016-07-14T10:14:33+02:002016-07-13|Coding, Raspberry Pi|

Raspberry Pi VNC mit X11VNC

Es gibt verschiedene VNC Lösungen für die Pi… Problem was ich oftmals dann habe ist, dass es sich nicht um die Screen-Session handelt, welche der User an HDMI hat.

Mit X11VNC kann man sich auf diese Session aber verbinden.

Lange habe ich damit gekämpft wie man X11VNC direkt beim Start / Booten laufen lässt.

Anbei meine Lösung welche ich hier abgeschaut habe :^)

X11VNC installieren

sudo apt-get install x11vnc

 

Datei erstellen für Autostart

touch /home/pi/.config/autostart/x11vnc.desktop
nano /home/pi/.config/autostart/x11vnc.desktop

 

Inhalt der Datei

[Desktop Entry]
Type=Application
Name=X11VNC
Exec=x11vnc -usepw -forever -display :0
StartupNotify=false

 

Neustart

sudo reboot
Von |2016-07-13T14:34:46+02:002016-07-13|Coding, Raspberry Pi|

Entity Framework MySql mit SSH-Tunnel in Mono

Der Titel sagt schon dass es nicht gerade das ist was man gerne programmiert…

Kurz zu meiner Anwendung:
Ich möchte gerne Werte von einem Raspberry Pi auf meinem Uberspace in einer MySql Datenbank speichern. Erst wollte ich das auf Azure tun, leider wird hier Mono noch nicht korrekt unterstützt.

Dann eben in MySql… aber Uberspace lässt Zugriff auf die Datenbank nur per SSH zu.

Gut, dann bauen wir uns mal einen SSH-Tunnel in Mono. Hier gibt es ein schönes NuGet-Packeg namens SSH.NET

Die Objekte wie folgt initialisieren:

private const string passwordSsh = "myPassword";
private const string username = "myUsername";
private const string server = "my.server.de";
static ForwardedPort port = new ForwardedPortLocal("localhost", 3306, "localhost", 3306);
private static SshClient sshClient = new SshClient(server, 22, username, passwordSsh);

Den Port benötigen wir um später die Daten durch Port 3306 zu tunneln.

 

Die Verbindung ist dann relativ einfach:

if (!sshClient.IsConnected)
{
    sshClient.Connect();

    // offline
    if (sshClient.IsConnected)
    {
        // Start port if not started
        if (!port.IsStarted)
        {
            // Add port if not added yet
            if (!sshClient.ForwardedPorts.Contains(port))
            {
                sshClient.AddForwardedPort(port);
            }
            port.Start();
        }
    }
}

Jetzt schnell noch das Entity Framework (Code First) einbinden und fertig … dachte ich.

Leider kommt mir das alle ziemlich buggy und nicht fertig vor. Drum weiß ich nicht ob ich das wirklich in einer Produktivumgebung einsetzten werde / würde.

Per NuGet gibt es MySql packages … aber welche brauche ich?
Bin selbst noch nicht durchgestiegen was für was ist, kann aber sagen, bei mir hat es nur mit folgenden geklappt:

  <package id="EntityFramework" version="6.1.3" targetFramework="net4" />
  <package id="MySql.Data" version="6.8.7" targetFramework="net4" />
  <package id="MySql.Data.Entities" version="6.8.3.0" targetFramework="net4" />

Nun gibt es aber noch einen Bug der unter einer Mono-Runtime die Version des Servers falsch parsed, somit braucht man folgenden fix (hab es bisl erweitert dass jeder Server/Version richtig gewandelt wird):

using System.Data;
using System.Data.Common;
using System.Data.Entity.Infrastructure;
using System.Text.RegularExpressions;

namespace OpenHop.Database
{
    public class ManifestTokenResolver : IManifestTokenResolver
    {
        public string ResolveManifestToken(DbConnection connection)
        {
            try
            {
                connection.Open();
                string version = OnlyNumbers(connection.ServerVersion);
                return version;

            }
            finally
            {
                if (connection.State == ConnectionState.Open)
                {
                    connection.Close();
                }
            }
        }

        private static readonly Regex digitsOnly = new Regex(@"[^\d]");
        public static string OnlyNumbers(string text)
        {
            return digitsOnly.Replace(text, "");
        }
    }
}

 

In der app.config dann noch die Daten eintragen:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
      <provider invariantName="MySql.Data.MySqlClient.EF6" type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.Entity.EF6, Version=6.8.3.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
    <provider invariantName="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.Entity.EF6, Version=6.9.8.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d">
      </provider></providers>
  </entityFramework>
  <connectionStrings>
    <add name="MyContext" providerName="MySql.Data.MySqlClient.EF6" connectionString="server=localhost;database=myDatabase;uid=myUsername;pwd=myPassword" />
  </connectionStrings>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="MySql.Data" publicKeyToken="c5687fc88969c44d" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-6.8.7.0" newVersion="6.8.7.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <system.data>
    <DbProviderFactories>
      <add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient.EF6" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory,MySql.Data, Version=6.8.1.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
    <remove invariant="MySql.Data.MySqlClient" /><add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.9.8.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" /></DbProviderFactories>
  </system.data>
</configuration>
Von |2015-11-02T11:14:25+01:002015-11-02|C#, Mono, Raspberry Pi|

Doorbell – Update: Pushbullet

Aufgrund eines Kommentars habe ich mir mal den Dienst Pushbullet angesehen.

Vorteil ist hier dass es eine Vorschau für Dateien (wie in unserem Fall Bilder) gibt.

Pushbullet

Leider gab es genau bei meinem Test ein Problem mit Pushnotifications unter iOS 8 … der Bug scheint behoben zu sein, dennoch pusht der Dienst nicht so zuverlässig wie Pushover. Ich teste nun ein bisschen mit beiden Diensten gleichzeitig. Aber eine Vorschau der Bilder ist natürlich schon ein Vorteil.

# Pushbullet
print("--> Pushbullet")
logger.info("--> Pushbullet")
pb = PushBullet("API-Token")

with open('/home/pi/Desktop/doorbell/web/photos/' +  filename, "rb") as pic:
    success, file_data = pb.upload_file(pic, filename + '.jpg')

success, push = pb.push_file(**file_data)
Von |2014-10-07T12:00:49+02:002014-10-07|Doorbell, Projekte, Raspberry Pi|
Nach oben