Schnäppchen

Kategorien

Raspberry Pi: i2c Devices fehlen

Wenn bei dir auch nach einem Raspbian-Update plötzlich die i2c Devices im Raspberry (/dev/i2c*) verschwunden sind, dann lies am besten diesen Artikel: I2C, SPI, I2S, LIRC, PPS, stopped working? Read this

Oder – wenn’s schnell gehen soll – aktiviere im raspi-config unter “Advanced Options” den Menüpunkt i2c (“Enable/Disable automatic loading of I2C kernel module”). Gleiches gilt entsprechend für SPI, I2S, LIRC-RPI und PPS-GPIO.

Linux Desktop auf ein Android Gerät exportieren

Für ein Raspberry-Projekt ohne eigenen Monitor hätte ich gerne die Möglichkeit über mein Tablet auf den Desktop des Linux-Rechners zugreifen zu können. Dafür gibt es verschidene Möglichkeiten. Eine einfach und schnell realisierbare Möglichkeit ist das Remote Desktop Protocol (RDP) von Microsoft. Dazu muss auf dem Linux-Rechner das Paket xrdp installiert werden. Auf dem Raspberry Pi unter Raspbian (und auch unter Ubuntu) geht das so:

sudo apt-get install xrdp

Nun muss dem Android-Gerät noch das RDP Protokoll beigebracht werden. Dafür gibt es zum Beispiel das Programm FreeRDP (hier bei Google Play). Nach der Installation müssen in der App noch die Zugangsdaten zum Linux-Rechner (Hostname, Port 3389, Benutzername, Passwort) eingegeben werden und schon kann es losgehen.

Ich bin nicht ganz sicher, wie robust das RDP Protokoll gegen Angriffe ist. Beispielsweise merkt FreeRDP nicht, wenn ich den Raspberry Pi mit einer anderen SD-Karte (aber gleichen Zugangsdaten) starte. Bei ssh muss ich nach einem Wechsel jedes mal den entsprechenden Eintrag in den known-hosts löschen. Für den schnellen Zugriff auf den Remote Desktop ist die RDP-Variante allerdings bestens geeignet.

Linux: Binärdateien mit cat ansehen

Bevor ich’s wieder vergesse: Binärdateien guckt man sich mit cat an, indem man sie per Pipe an od weiter leitet:

Zum Beispiel
cat DATEI | od # Anzeige in Oktal
cat DATEI | od -x # Anzeige in Hexadezimal

Von mir aus auch gleich:
od DATEI
oder
od -x DATEI

ownCloud vs. Nextcloud

In der ownCloud-Community scheint es gehörig zu rumpeln. Da ich ownCloud intensiv nutze sollte ich wohl versuchen da auf dem Laufenden zu bleiben…

Weblinks:

Android: Display Helligkeit im eigenen Programm ändern

Android Apps können die Display-Helligkeit relativ einfach ändern. Voraussetzung ist allerdings, dass der entsprechenden App der Zugriff auf die System-Einstellungen gewährt wurde. Die App muss dieses Recht also im AndroidManifest.xml einfordern:

<uses-permission android:name="android.permission.WRITE_SETTINGS" />

Die aktuelle Helligkeits-Einstellung kann dann leicht so erfragt

brightness = android.provider.Settings.System.getInt(getContentResolver(), android.provider.Settings.System.SCREEN_BRIGHTNESS);

und so

android.provider.Settings.System.putInt(getContentResolver(), android.provider.Settings.System.SCREEN_BRIGHTNESS, new_brightness);

gesetzt werden. Der Helligkeit-Wert kann dabei zwischen 0 und 255 liegen.

Mit diesem kleinen Android Studio Projekt auf Github kann man zum Beispiel die Bildschirm-Helligkeit mit einem Slider (SeekBar) zwischen 0 und 255 einstellen.

Android SQLite: Umlaute richtig sortieren

Soweit ich weiß kann SQLite Umlaute von Haus aus nicht richtig sortieren. Nach einiger Suche habe ich beim Android-SQLite aber doch eine Möglichkeit gefunden:

SELECT blabla FROM table ORDER BY blabla COLLATE LOCALIZED

oder auch

SELECT blabla FROM table ORDER BY blabla COLLATE LOCALIZED ASC

SELECT blabla FROM table ORDER BY blabla COLLATE LOCALIZED DESC

Lösung: Android Browser stürzen ständig ab

Bei meinem Tablet habe ich in letzter Zeit das Problem, dass die Browser (sowohl der Standart-Browser als auch Firefox und Chrome) immer mal wieder unmotiviert abstürzen. Angeblich liegt das an einem überlasteten System. Aber auch nachdem ich etliche laufende Prozesse gelöscht und die Caches gelöscht hatte ließ sich das Problem nicht lösen. Deshalb habe ich beim Firefox mal Javascript deaktiviert. Seit dem läuft zumindest der Firefox wieder stabil.

Leider ist die Option zum Deaktivieren von Javascript nicht unter den Einstellungen zu finden. Deshalb hier eine kleine Anleitung:

Wie beim Firefox auf dem Desktop gibt es auch beim “kleinen” Firefox eine about:config Seite. Man gibt also in der Adresszeile about:config ein und drückt Enter. Anschließend scrollt man herunter bis zum Eintrag javascript.enabled und schaltet ihn von true auf false. Das wars.

Da es in about:config wirklich sehr viele Einstellungsmöglichkeiten gibt ist es übrigens einfacher im der Suche nach javascript zu suchen anstatt zu scrollen.

Bidirektionale serielle Kommunikation zwischen Arduino und PC

Für ein Projekt (nämlich unser Zimmergewächshaus) brauchte ich eine vernünftige Möglichkeit aus einem C++ Programm auf einem Linux-PC bidirektional mit dem Arduino zu kommunizieren. Eigentlich ist das natürlich kein unlösbares Problem. Trotzdem hat es etwas gedauert, bis das bei mir reibungslos funktionierte.

Die hier vorgestellte Test-Umgebung macht folgendes: Die Zeichen, die auf dem PC eintipperten wurden werden zum Arduino übertragen. Dort werden sie zeilenweise gesammelt und dann zurück zum PC übertragen.

Dieses ist ein Test
Arduino: Dieses ist ein Test

Um das Ganze etwas besser testen zu können, werden die Ziffern 1 bis 5 auf dem PC vor der Übertragung in Worte (“eins” bis “fünf”) gewandelt. Die Ziffern 6 bis 0 werden ganz normal übertragen, dann aber auf dem Arduino in die entsprechenden Worte gewandelt.

Ziffern 0 1 2 3 4 5 6 7 8 9
Arduino: Ziffern null eins zwei drei vier fünf sechs sieben acht neun

Hier zunächst der Arduino-Sketch:

// ----------------------------------------------
//  Project Arduino/PC Serial Communication  
// ----------------------------------------------
// Just some code to test serial communication
// between Arduino and PC
//
// Version
//   minicom 2014.02.06
// 
// Author:
//   Heiner Otterstedt <h.otterstedt@gmail.com>
//
// Website:
//   http://maheo.eu
//

char szInstruction[128];
int  iInstruction = 0;

void setup()
{ Serial.begin(9600);
}

void loop()
{ if(Serial.available())
  { while(Serial.available())
    { szInstruction[iInstruction] = Serial.read();
      if(szInstruction[iInstruction] == '6')
      { strcpy(&szInstruction[iInstruction], "sechs");
        iInstruction += 4;
      }
      else if(szInstruction[iInstruction] == '7')
      { strcpy(&szInstruction[iInstruction], "sieben");
        iInstruction += 5;
      }
      else if(szInstruction[iInstruction] == '8')
      { strcpy(&szInstruction[iInstruction], "acht");
        iInstruction += 3;
      }
      else if(szInstruction[iInstruction] == '9')
      { strcpy(&szInstruction[iInstruction], "neun");
        iInstruction += 3;
      }
      else if(szInstruction[iInstruction] == '0')
      { strcpy(&szInstruction[iInstruction], "null");
        iInstruction += 3;
      }

      if(szInstruction[iInstruction] == '\n' ||
         szInstruction[iInstruction] == 'q' ||
         ++iInstruction >= 120)
      { szInstruction[iInstruction] = 0;
        iInstruction = 0;
        doSomething(szInstruction);
      }
    }
  }
}

void doSomething(char *psz)
{ Serial.print  ("Arduino: ");
  Serial.println(szInstruction);
}

Das C++ Programm auf dem Linux-PC habe ich im Prinzip aus einem Beitrag in der Boost Mailingliste (siehe hier bei Nabble) abgeleitet. Der User Jeff Gray-3 hatte dort den Code für ein einfaches MiniCom Programm gepostet. Erwartungsgemäß verwendet das Programm Teile der Boost Bibliothek. Die entsprechenden Librarys müssen also beim Aufruf des Compilers angegeben werden:

g++ -lboost_system-mt -lboost_thread-mt -o minicom minicom.cpp

Hier mein modifizierter Code:

/* minicom.cpp
 *      A simple demonstration minicom client with Boost asio
 *
 *      Parameters: baud port
 *      To end the application, send Ctrl-C on standard input
 *
 * Info
 *   http://boost.2283326.n4.nabble.com/Simple-serial-port-demonstration-with-boost-asio-asynchronous-I-O-td2582657.html
 *
 * Compile:
 *   g++ -lboost_system-mt -lboost_thread-mt -o minicom minicom.cpp
 *
 * Author:
 *   Jeff Gray-3 (http://boost.2283326.n4.nabble.com/Simple-serial-port-demonstration-with-boost-asio-asynchronous-I-O-td2582657.html)
 *
 *   modified by Heiner Otterstedt (maheo.eu)
 */

#include <deque>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/asio/serial_port.hpp>
#include <boost/thread.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>

#ifdef POSIX
#include <termios.h>
#endif

using namespace std;

class minicom_client
{
public:
  minicom_client(boost::asio::io_service& io_service, unsigned int baud, const string& device)
                : active_(true),
                  io_service_(io_service),
                  serialPort(io_service, device)
  { if (!serialPort.is_open())
    { cerr << "Failed to open serial port\n";
      return;
    }
    boost::asio::serial_port_base::baud_rate baud_option(baud);
    serialPort.set_option(baud_option); // set the baud rate after the port has been opened
    read_start();
  }

  void write(const char msg) // pass the write data to the do_write function via the io service in the other thread
  { io_service_.post(boost::bind(&minicom_client::do_write, this, msg));
  }

  void write(const string s)
  { int i;

    for(i=0; i<s.length(); i++)
      { write((const char)s.at(i));
    }

  }

  void close() // call the do_close function via the io service in the other thread
  { io_service_.post(boost::bind(&minicom_client::do_close, this, boost::system::error_code()));
  }

  bool active() // return true if the socket is still active
  { return active_;
  }

private:

  static const int max_read_length = 512; // maximum amount of data to read in one operation

  void read_start(void)
  { // Start an asynchronous read and call read_complete when it completes or fails
    serialPort.async_read_some(boost::asio::buffer(read_msg_, max_read_length),
                        boost::bind(&minicom_client::read_complete,
                                this,
                                boost::asio::placeholders::error,
                                boost::asio::placeholders::bytes_transferred));
  }

  void read_complete(const boost::system::error_code& error, size_t bytes_transferred)
  { // the asynchronous read operation has now completed or failed and returned an error
    if (!error)
    { // read completed, so process the data
      cout.write(read_msg_, bytes_transferred); // echo to standard output
      read_start(); // start waiting for another asynchronous read again
    }
    else
      do_close(error);
  }

  void do_write(const char msg)
  { // callback to handle write call from outside this class
    bool write_in_progress = !write_msgs_.empty(); // is there anything currently being written?
    write_msgs_.push_back(msg); // store in write buffer
    if (!write_in_progress) // if nothing is currently being written, then start
      write_start();
  }

  void write_start(void)
  { // Start an asynchronous write and call write_complete when it completes or fails
    boost::asio::async_write(serialPort,
                        boost::asio::buffer(&write_msgs_.front(), 1),
                        boost::bind(&minicom_client::write_complete,
                                this,
                                boost::asio::placeholders::error));
  }

  void write_complete(const boost::system::error_code& error)
  { // the asynchronous read operation has now completed or failed and returned an error
    if (!error)
    { // write completed, so send next write data
      write_msgs_.pop_front(); // remove the completed data
      if (!write_msgs_.empty()) // if there is anthing left to be written
        write_start(); // then start sending the next item in the buffer
    }
    else
      do_close(error);
  }

  void do_close(const boost::system::error_code& error)
  { // something has gone wrong, so close the socket & make this object inactive
    if (error == boost::asio::error::operation_aborted) // if this call is the result of a timer cancel()
       return; // ignore it because the connection cancelled the timer

    if (error)
       cerr << "Error: " << error.message() << endl; // show the error message
    else
       cout << "Error: Connection did not succeed.\n";

    cout << "Press Enter to exit\n";
    serialPort.close();
    active_ = false;
  }

private:
  bool active_; // remains true while this object is still operating
  boost::asio::io_service& io_service_; // the main IO service that runs this connection
  boost::asio::serial_port serialPort; // the serial port this instance is connected to
  char read_msg_[max_read_length]; // data read from the socket
  deque<char> write_msgs_; // buffered write data
};

int main(int argc, char* argv[])
{
// on Unix POSIX based systems, turn off line buffering of input, so cin.get() returns after every keypress
// On other systems, you'll need to look for an equivalent
#ifdef POSIX
  termios stored_settings;
  tcgetattr(0, &stored_settings);
  termios new_settings = stored_settings;
  new_settings.c_lflag &= (~ICANON);
  new_settings.c_lflag &= (~ISIG); // don't automatically handle control-C
  tcsetattr(0, TCSANOW, &new_settings);
#endif
  try
  {
    if (argc != 3)
    {
      cerr << "Usage: minicom <baud> <device>\n";
      return 1;
    }
    boost::asio::io_service io_service;

    // define an instance of the main class of this program
    minicom_client c(io_service, boost::lexical_cast<unsigned int>(argv[1]), argv[2]);

    // run the IO service as a separate thread, so the main thread can block on standard input
    boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));

    while (c.active()) // check the internal state of the connection to make sure it's still running
    { char ch;
      cin.get(ch); // blocking wait for standard input
      if (ch == 3) // ctrl-C to end program
         break;

      // Testing strings...
      if(ch == '1')      { string s = "eins"; c.write(s); }
      else if(ch == '2') { string s = "zwei"; c.write(s); }
      else if(ch == '3') { string s = "drei"; c.write(s); }
      else if(ch == '4') { string s = "vier"; c.write(s); }
      else if(ch == '5') { string s = "fünf"; c.write(s); }
      else               {                    c.write(ch); }
    }
    c.close(); // close the minicom client connection
    t.join(); // wait for the IO service thread to close
  }
  catch (exception& e)
  { cerr << "Exception: " << e.what() << "\n";
  }
#ifdef POSIX // restore default buffering of standard input
  tcsetattr(0, TCSANOW, &stored_settings);
#endif
  return 0;
}

Das fertige Programm wird mit den Parametern Baudrate und Port aufgerufen, also zum Beispiel

minicom 9600 /dev/ttyUSB0

für einen Arduino Duemilanove oder

minicom 9600 /dev/ttyACM0

für einen Arduino Uno.

Erweiterbare Adsense-Anzeigen ausschalten

Adsense Overlay-Ad

Auf unserem Gartenblog erscheinen plötzlich riesige Overlay-Ads, wenn man über bestimmte Anzeigen hoovert. Echt furchtbar sowas!

Um das abzuschalten musste ich ziemlich lange suchen. Deshalb hier eine kurze Anleizung:

  • Im Adsense Kontrollzentrum geht man auf “Anzeigen zulassen und blockieren“.
  • Anschließend wählt man oben den Punkt “Anzeigenschaltung” auf.
  • dort kann man unten die Option “Erweiterbare Anzeigen – Schaltung von Anzeigen, die durch eine Nutzeraktion über die Größe des Anzeigenblocks hinaus erweitert werden können” ausschalten.

Wieso das versehentliche überqueren einer Anzeige schon eine “Nutzerreaktion” ist, bleibt wohl das Geheimnis von Google.

Debian: IP-Adresse ändern

Um die IP-Adresse eines Debian-Rechners zu ändern wird die neue Adresse zunächst in /etc/network/interfaces eingetragen. Zum Beispiel so:

address 192.168.42.12

Anschließend wird das Netzwerk neu gestartet:

/etc/init.d/networking restart

Vorsicht, wenn man das per ssh macht, ist Verbindung nun logischerweise weg ;-)