Archiv für den Monat: Dezember 2021

Handlicher Suchscheinwerfer

Ich hab mir eine helle Taschenlampe eingebildet.

Da kam mir die Astrolux EC06 im Angebot mit Gutschein für ~64 Euro gerade recht.

Die Lampe ist so groß wie ca. eine Getränkedose 0,33l.

Da drin liefern 3x 21700er LiIonen-Zellen (nicht mitgeliefert) den Saft.

6x Cree XHP50.2 machen Licht. Eine solche kann bis zu 2654lm erreichen. Die Lampe wird mit bis zu 16000lm beworben, könnte also stimmen. Der Strahl ist recht breit.

Die Lampe wiegt leer schon fast 500g.

Man kann sie auch mit USB laden.

Die Steuerung ist Open-Source, Anduril 2. Einfach, aber sehr mächtig.

Wenn man sie anschaltet, ist sie ganz zahm. Per Doppelklick entfaltet sie erst die volle Power – da geht dann die Sonne auf. Es ist blendend hell!

Wifi-GPS-Topspeed-Meter

Arduino on Lilygo OLED Lora ESP32 (board TTGO-Lora32-OLED V1″)

#define USE_OLED

#ifdef USE_OLED
//Libraries for OLED Display
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#endif

#include <WiFi.h>
#include <WiFiClient.h>
#include <WiFiAP.h>

const char *ssid = "GPSWIFI";
const char *password = "12345678";

WiFiServer server(80);

const unsigned char ubxRate1Hz[]  = 
  { 0x06,0x08,0x06,0x00,0xE8,0x03,0x01,0x00,0x01,0x00 };
const unsigned char ubxRate5Hz[]  =
  { 0x06,0x08,0x06,0x00,200,0x00,0x01,0x00,0x01,0x00 };
const unsigned char ubxRate10Hz[]  =
  { 0x06,0x08,0x06,0x00,100,0x00,0x01,0x00,0x01,0x00 };
const unsigned char ubxRate16Hz[]  =
  { 0x06,0x08,0x06,0x00,50,0x00,0x01,0x00,0x01,0x00 };

// Disable specific NMEA sentences
const unsigned char ubxDisableGGA[]  =
  { 0x06,0x01,0x08,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x01 };
const unsigned char ubxDisableGLL[]  =
  { 0x06,0x01,0x08,0x00,0xF0,0x01,0x00,0x00,0x00,0x00,0x00,0x01 };
const unsigned char ubxDisableGSA[]  =
  { 0x06,0x01,0x08,0x00,0xF0,0x02,0x00,0x00,0x00,0x00,0x00,0x01 };
const unsigned char ubxDisableGSV[]  =
  { 0x06,0x01,0x08,0x00,0xF0,0x03,0x00,0x00,0x00,0x00,0x00,0x01 };
const unsigned char ubxDisableRMC[]  =
  { 0x06,0x01,0x08,0x00,0xF0,0x04,0x00,0x00,0x00,0x00,0x00,0x01 };
const unsigned char ubxDisableVTG[]  =
  { 0x06,0x01,0x08,0x00,0xF0,0x05,0x00,0x00,0x00,0x00,0x00,0x01 };
const unsigned char ubxDisableZDA[]  =
  { 0x06,0x01,0x08,0x00,0xF0,0x08,0x00,0x00,0x00,0x00,0x00,0x01 };


#define Battadc 36
#define ADC_FACTOR (0.000635*2.0*1.362)
#define BATT_LOW 3.5

#define SDA 21
#define SCL 22

#ifdef USE_OLED
//OLED pins
#define OLED_SDA 4
#define OLED_SCL 15 
#define OLED_RST 16
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RST);
#endif

bool enable_dbg;
bool sig_valid, sig_rxok;
float sig_speed, saved_spd;
int sig_sats;
#define NUM_V_ENTRIES 5
float maxspeed[NUM_V_ENTRIES];
int vbatt;

// Cut out the wanted substring from a comma-separated string
static String extract_val(char *buf, int len, int cpos)
{
  String str="";
  int i,cc=0,cs=0,ce=255;
  for (i=0;i<len;i++) {
    if (buf[i]==',') {
      cc++; // count commas
      if(cc==cpos) cs=i+1;
      if(cc==cpos+1) {ce=i; break;}
    }
    else if (buf[i]=='*' || buf[i]=='\r')
      ce=i;
  }
  if (cs == 0) // no comma seen - no result
    return str;
  int s = min(ce-cs, 255);
  for (i=0; i<s; i++) // build string, could be nicer...
    str+=(char)buf[cs+i];
//  memcpy(tgt, &buf[cs], s);
  return str;
}

void parse_gps(char c) {
  static char buf[127];
  static int pos=0;
  if (c=='\n') {
    buf[pos]=0;
    if (buf[2]=='V' && buf[3]=='T' && buf[4]=='G') {
      sig_rxok = true;
      String s = extract_val(buf, pos, 7);
      if (s.length() > 0)
        sig_valid = true;
      Serial.println(s);
      sig_speed = s.toFloat();
      saved_spd = sig_speed;
    }
    else if (buf[2]=='G' && buf[3]=='G' && buf[4]=='A') {
#ifdef USE_OLED
      display.print(buf);
#endif
      String s = extract_val(buf, pos, 7);
      Serial.println(s);
      sig_sats = s.toInt();
    }
  }
  else if (c=='$') pos=0;
  else if (pos < sizeof(buf))
    buf[pos++] = c;
}

//Warteschleife, die ankommende Daten vom GPS Modul verarbeitet und den Status des Tasters prüft
static void smartdelay(unsigned long ms)
{
  unsigned long start = millis();
  do 
  {
    while (Serial2.available()) {
      char c=Serial2.read();
      parse_gps(c);
      if (enable_dbg) Serial.print(c);
      //display.print(c);
    }
    //display.display();
  } while (millis() - start < ms);
}

static void sendUBX( const unsigned char *progmemBytes, size_t len )
{
  Serial2.write( 0xB5 ); // SYNC1
  Serial2.write( 0x62 ); // SYNC2

  uint8_t a = 0, b = 0;
  while (len-- > 0) {
    uint8_t c = ( *progmemBytes++ );
    a += c;
    b += a;
    Serial2.write( c );
  }

  Serial2.write( a ); // CHECKSUM A
  Serial2.write( b ); // CHECKSUM B
  delay(100);
}

static void updateRate()
{
  sendUBX(ubxRate5Hz, 10);
}

void setup() { 
  pinMode(0, INPUT_PULLUP); // button
  pinMode(SCL, INPUT_PULLUP); // I2C of GPS compass
  pinMode(SDA, INPUT_PULLUP);

//  analogSetAttenuation(ADC_0db); // control sensitivity; ADC_11db, ADC_6db, ADC_2_5db, ADC_0db
//  pinMode(Battadc, INPUT);
//  adcAttachPin(Battadc);

  Serial.begin(115200); // debug
  Serial2.begin(9600,SERIAL_8N1,12,13); // GPS
  
#ifdef USE_OLED
  //reset OLED display via software
  pinMode(OLED_RST, OUTPUT);
  digitalWrite(OLED_RST, LOW);
  delay(20);
  digitalWrite(OLED_RST, HIGH);

  //initialize OLED
  Wire.begin(OLED_SDA, OLED_SCL);
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3c, false, false)) { // Address 0x3C for 128x32
    //Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
#endif

  // setup WIFI server
  WiFi.softAP(ssid, password);
  IPAddress myIP = WiFi.softAPIP(); // usually 192.168.4.1
  server.begin();

#ifdef USE_OLED
  display.setTextColor(WHITE);
  display.setTextSize(1);
  display.clearDisplay();
  display.setCursor(0, 0);
  display.println("Simon's WIFI GPS");
  display.println("IP address:");
  display.println(myIP);
  display.display();
#endif

  delay(2000);
  sendUBX(ubxDisableGLL, 12);
  sendUBX(ubxDisableGSA, 12);
  sendUBX(ubxDisableGSV, 12);
  sendUBX(ubxDisableRMC, 12);
  sendUBX(ubxDisableZDA, 12);
  Serial2.print("$PUBX,41,1,0007,0003,19200,0*25\r\n");
  Serial2.flush();
  delay(100);
  Serial2.end();
  Serial2.begin(19200,SERIAL_8N1,12,13);
  delay(1000);
  updateRate();
}

void wifi() {
  WiFiClient client = server.available();   // listen for incoming clients

  if (client) {                             // if you get a client,
    char i;
    Serial.println("New Client.");           // print a message out the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
//        Serial.write(c);                    // print it out the serial monitor
        if (c == '\n') {                    // if the byte is a newline character

          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println();

            // the content of the HTTP response follows the header:
            char tmp[32];
            client.print("<html><head><meta http-equiv=\"refresh\" content=\"10; URL=/\" /></head>");
            client.print("<body style=\"background-color:black;\"><h1 style=\"color:white;font-size:80px\">Simon's WIFI GPS</h1>");
            client.println("<p style=\"color:white;font-size:60px\"><b>");
            sprintf(tmp, "Max = %4.1f km/h", maxspeed[0]);
            client.print(tmp);
            client.println("</p><p style=\"color:white;font-size:30px\">");
            for (i=1;i<NUM_V_ENTRIES;i++) {
              sprintf(tmp, "%4.1f km/h", maxspeed[i]);
              client.print(tmp);
              client.println("<br>");
            }
            sprintf(tmp, "<br>Batt = %2.3f V", (float)vbatt*ADC_FACTOR);
            client.print(tmp);
            client.println("<br>");

            sprintf(tmp, "<br>Signal rx ok = %d", sig_rxok);
            client.print(tmp);
            client.println("<br>");

            sprintf(tmp, "<br># of satellites = %d", sig_sats);
            client.print(tmp);
            client.println("<br>");

            client.print("<br><br><a href=\"/R\">RESET</a> Vmax.<br></p></body></html>");

            // The HTTP response ends with another blank line:
            client.println();
            // break out of the while loop:
            break;
          } else {    // if you got a newline, then clear currentLine:
            currentLine = "";
          }
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }

        // Check to see if the client request was "GET /H" or "GET /L":
        if (currentLine.endsWith("GET /R")) {
          for (i=0; i<NUM_V_ENTRIES; i++)
            maxspeed[i] = 0.0;
        }
      }
    }
    // close the connection:
    client.stop();
//    Serial.println("Client Disconnected.");
  }
}

void loop() {
  int i;
  bool spdwritten = false;
  char tmp[32];
  float spd;
  
  smartdelay(0);
#ifdef USE_OLED
  display.clearDisplay(); // drawString(x,y,text);? or ACROBOTIC_SSD1306 with setTextXY/putString
  display.setCursor(0, 0);
#endif
  if (sig_valid) {
    spd = sig_speed;
    sig_speed = 0.0;
    // show maximum speed, with 5 places to see glitches
#ifdef USE_OLED
    display.println("Geschwindigkeit (max)");
#endif
    for (i=0; i<NUM_V_ENTRIES; i++) {
      if (spd > maxspeed[i] && !spdwritten) {
        maxspeed[i] = spd;
        spdwritten = true;
        break;
      }
    }
#ifdef USE_OLED
    for (i=0; i<NUM_V_ENTRIES; i++) {
      if (i==0)
        display.setTextSize(2);
      sprintf(tmp, "%4.1f km/h", maxspeed[i]);
      display.println(tmp);
      if (i==0)
        display.setTextSize(1);
    }
    // show current speed
    sprintf(tmp,"S%4.1f  Sats %3d", saved_spd, sig_sats);
    display.print(tmp);
  } else {
    display.println("No GPS fix.");
    if (sig_rxok)
      display.println("GPS RX ok");
    sprintf(tmp,"         Sats %3d", sig_sats);
    display.print(tmp);
#endif
  }
  vbatt = analogRead(Battadc);
#ifdef USE_OLED
  if ((float)vbatt*ADC_FACTOR < BATT_LOW) {
    display.setCursor(108, 32);
    display.print("LOW");
  }
  display.display();
#endif
  if (digitalRead(0)==0) { // clear
    for (i=0;i<NUM_V_ENTRIES; i++)
      maxspeed[i] = 0.0;
#ifdef USE_OLED
    display.clearDisplay();
#endif
  }
  wifi();
}

Linux DLNA-Server

installiere minidlna (nach https://wiki.ubuntuusers.de/ReadyMedia/)

sudo apt-get install minidlna

setze interface z.B. wlo1

network_interface=wlo1
friendly_name=Laptop
inotify=yes
media_dir=V,/var/lib/minidlna/videos
media_dir=A,/var/lib/minidlna/music

kopiere Zeug in /var/lib/minidlna

gib Rechte 644 auf die Dateien

find /var/lib/minidlna/videos -type f -exec chmod 0644 {} \;

restart server