Catfood WebCamSaver 3.28
Catfood WebCamSaver 3.28 is available to download.
This release updates the webcam list.
Catfood WebCamSaver 3.28 is available to download.
This release updates the webcam list.
Timelapse of stars over Casini Ranch, a campground near Duncan Mills in Sonoma, California. Shot over two nights looking north-east and then south-west from the bank of the Russian River.
(Published to the Fediverse as: Stars over Casini Ranch, a Timelapse #timelapse #video #stars 4k time lapse of stars over Casini Ranch on Duncan Mills, Sonoma, California. Shot next to the Russian River over two nights. )
Three stormy sunsets in Bangalore. Shot between May 8 and 14, 2022 from the Shangri-La Hotel.
(Published to the Fediverse as: Bangalore Sunsets #timelapse #video #bangalore #india #4k 4K 60fps timelapse of three sunsets in Bangalore (Bengaluru) in Karnataka, India shot from the Shangri-La Hotel. )
nobody:
me: What if I used a year of global cloud cover images to make an animation where each frame is the average of the past 24 hours?
The animation covers August 2020 to August 2021. See this video for a version without the averaging (and with the Earth's surface).
The averaged version shows some interesting cycles better than the frenetic pace of hourly cloud cover. In my area you can really see the high pressure off the coast of California that sends any rain off to our friends in Seattle.
Images are from the University of Wisconsin-Madison Space Science and Engineering Center, specifically the Global IR product, transformed as described here.
(Published to the Fediverse as: Daily Average Global Cloud Cover Animation #timelapse #video #clouds Time lapse video of a year of global cloud cover where each frame is the average of the past 24 hours. )
Shots are: north to Mount Tamalpais from Golden Gate Heights park, south-west from Grand View Park, north from Grand View, south from Grand View, north again from Grand View and finally east from Grand View (if you look closely something is being hauled up Sutro Tower).
(Published to the Fediverse as: TLOTW #7 #timelapse #video #tamalpais #tlotw #goldengateheights #grandview #sutrotower Time lapse of the week number seven, includes shots from Golden Gate Heights and Grand View parks in San Francisco, California. )
Google Pixel 6 Pro 19mm f3.5 1/250s ISO33
Brief moment of calm before a 737 knocks the Moon into Sutro Tower. Almost.
In this ethereal composition titled "Sutro Tower, Moon, and Plane," we observe a juxtaposition of human engineering and celestial wonders against an expansive sky. The Sutro Tower stands prominently in the left portion of the frame, its intricate lattice structure a testament to human craftsmanship. To its right, a waning moon hangs quietly, casting a soft, luminous glow that speaks of tranquility in contrast to the rigid lines of the tower. A small plane appears almost playful, captured mid-flight as it slices through these two primary subjects, adding a dynamic element to the scene. The sky's vibrant blue serves as a serene backdrop, unifying these disparate elements into a harmonious whole.
The photograph employs a balanced composition, with the Sutro Tower anchoring the left side, providing a structural counterpoint to the more ephemeral moon. The rule of thirds is subtly at play here, with the tower and moon occupying strong compositional positions, drawing the viewer’s eye naturally across the image. The plane, although smaller, punctuates the scene, adding a sense of movement and scale. The use of color is particularly striking - the bright blue sky provides high contrast with the dark, textured tower, and highlights the crisp white of the plane. However, the image could benefit from slight adjustments in contrast to further distinguish the moon from the rich azure of the sky. Overall, the photograph succeeds in creating a compelling narrative about the intersection of the terrestrial and the celestial, though it might press further into this intersection through more dramatic lighting or angles.
(Published to the Fediverse as: Sutro Tower, Moon, and Plane #photo #sutrotower #moon Photo of a plane that looks like it's about to knock the moon into Sutro Tower in San Francisco, California. )
Save America’s Patent System
Good problem to solve, wrong solution. Examine patents on use rather than before issuing.
After a few experiments I have a pretty decent platform for capturing long term time lapse footage. The system is designed to run for around a month and captures a photo every thirty seconds during daylight hours. It's a fairly cheap build so I'm not too worried about theft or accidental damage. This post contains build instructions and sample code to get the camera up and running. Before that, here's a quick video made from a few test runs:
On the hardware side you need an Arduino Mega 2560 REV3, the OV5642 camera module, an SD module and card, a battery and a solar panel. You'll also want a waterproof case, cables and some zip ties. Everything I used is on this Amazon list. I tried a few different power solutions and the Voltaic Systems 6W solar panel + 6,400 mAh battery combination is ideal. Their battery banks are 'always on' and continue to provide power even when the Arduino isn't doing anything. Most battery banks shut down when there is low power usage. In my testing the 6W panel managed to keep the system running with no issues.
The main limitation is that Arduino only supports up to 32GB SD cards. With the code below this allows around a month of photos. Depending on the application you could go much longer - the variables are interval (I'm shooting a frame around every 30 seconds) and file size (lower resolution and/or JPEG quality). At some point I'd like to figure out cellular upload but for now 32GB will have to do.
Assembly is pretty easy. The OV5642 camera uses both the I2C and SPI buses. For I2C connect the pins labeled SCL and SDA to SCL and SDA on the Arduino Mega (D21 and D20 pins - search Arduino Mega pinout if necessary). The SPI connections are MISO, MOSI and SCK (available at D50, D51 and D52). You also need CS (chip select) - wire this to D10. Finally wire ground and power to the GND and 5V pins. The SD module also uses SPI. Wire its MISO, MOSI and SCK to the same pins (D50, D51 and D52). SD needs a separate CS (chip select), use D7. And finally for SD connect ground and power to GND and 5V. That's it.
The box linked above is large enough to fit all the components easily. You'll need to drill two holes, one for the camera lens and one for the solar panel cable. Once assembled, seal around both as well as you can.
To program the Mega you need to install the Arduino IDE and then download and install the ArduCAM library. Make sure that the ArduCAM folder is directly under the libraries folder for your Arduino IDE (on Windows this is probably C:\Program Files (x86)\Arduino\libraries\ArduCAM). Then open the file memorysaver.h in the ArduCAM folder and make sure that only the OV5642 line is uncommented (#define OV5642_MINI_5MP_PLUS). If you get build errors it's almost certainly this step that is the problem so check carefully.
At this point I'd suggest trying the blink sample to make sure that you can connect to and program your board successfully. Once this is working create a new sketch and then copy the code below:
#include <Wire.h> | |
#include <ArduCAM.h> | |
#include <SPI.h> | |
#include <SD.h> | |
#include <avr/power.h> | |
#include <avr/sleep.h> | |
#include "memorysaver.h" | |
//#define USE_SERIAL | |
const int CS = 10; // chip select pin for camera | |
const int SD_CS = 7; // chip select pin for SD reader | |
const int MaxWait = 100; // how long to wait during initialization | |
ArduCAM myCAM(OV5642, CS); | |
int filenum = 1; | |
uint8_t read_fifo_burst(ArduCAM myCAM); | |
void setup() { | |
uint8_t temp; | |
uint8_t vid, pid; | |
char fnbuf[15]; | |
int w = 0; | |
// configure minimal power usage | |
lowPowerSetup(); | |
// internal LED on during setup | |
digitalWrite(LED_BUILTIN, HIGH); | |
// start SPI bus | |
Wire.begin(); | |
// serial for debug messages, comment USE_SERIAL out above for release | |
#if defined USE_SERIAL | |
Serial.begin(115200); | |
while(!Serial) {} | |
sMessage(F("Serial connected.")); | |
#endif | |
// set camera chip select pin HIGH | |
pinMode(CS, OUTPUT); | |
digitalWrite(CS, HIGH); | |
// start SPI | |
SPI.begin(); | |
delay(100); | |
// reset CPLD | |
myCAM.write_reg(0x07, 0x80); | |
delay(100); | |
myCAM.write_reg(0x07, 0x00); | |
delay(100); | |
// wait for ArduCAM SPI | |
w = 0; | |
while(w < MaxWait) { | |
myCAM.write_reg(ARDUCHIP_TEST1, 0x55); | |
temp = myCAM.read_reg(ARDUCHIP_TEST1); | |
if (temp != 0x55){ | |
sMessage(F("Waiting for ArduCAM on SPI bus.")); | |
delayWithFlash(); | |
} else { | |
sMessage(F("Found ArduCAM on SPI bus.")); | |
break; | |
} | |
w++; | |
if (w >= MaxWait) { | |
sMessage(F("Waited too long, restarting.")); | |
delay(100); | |
reset(); | |
} | |
} | |
// detect ArduCAM | |
w = 0; | |
while(w < MaxWait) { | |
myCAM.wrSensorReg16_8(0xff, 0x01); | |
myCAM.rdSensorReg16_8(OV5642_CHIPID_HIGH, &vid); | |
myCAM.rdSensorReg16_8(OV5642_CHIPID_LOW, &pid); | |
if((vid != 0x56) || (pid != 0x42)){ | |
sMessage(F("Waiting to detect ArduCAM as OV5642.")); | |
delayWithFlash(); | |
} else{ | |
sMessage(F("Detected ArduCAM as OV5642.")); | |
break; | |
} | |
w++; | |
if (w >= MaxWait) { | |
sMessage(F("Waited too long, restarting.")); | |
delay(100); | |
reset(); | |
} | |
} | |
sMessage(F("Initializing ArduCAM OV5642.")); | |
myCAM.set_format(JPEG); | |
myCAM.InitCAM(); | |
myCAM.write_reg(ARDUCHIP_TIM, VSYNC_LEVEL_MASK); | |
sMessage(F("Size 2592x1944")); | |
myCAM.OV5642_set_JPEG_size(OV5642_2592x1944); | |
delay(1000); | |
sMessage(F("Advanced AWB")); | |
myCAM.OV5642_set_Light_Mode(Advanced_AWB); | |
delay(250); | |
sMessage(F("High Quality Compression")); | |
myCAM.OV5642_set_Compress_quality(high_quality); | |
delay(250); | |
sMessage(F("Saturation +1")); | |
myCAM.OV5642_set_Color_Saturation(Saturation1); | |
delay(250); | |
sMessage(F("Brightness 0")); | |
myCAM.OV5642_set_Brightness(Brightness0); | |
delay(250); | |
sMessage(F("Contrast +1")); | |
myCAM.OV5642_set_Contrast(Contrast1); | |
delay(250); | |
sMessage(F("Hue 0")); | |
myCAM.OV5642_set_hue(degree_0); | |
delay(250); | |
sMessage(F("Special Effects Normal")); | |
myCAM.OV5642_set_Special_effects(Normal); | |
delay(250); | |
sMessage(F("Exposure Default")); | |
myCAM.OV5642_set_Exposure_level(Exposure_default); | |
delay(250); | |
sMessage(F("Sharpness Auto + 1")); | |
myCAM.OV5642_set_Sharpness(Auto_Sharpness1); | |
delay(250); | |
myCAM.flush_fifo(); | |
myCAM.clear_fifo_flag(); | |
myCAM.write_reg(ARDUCHIP_FRAMES,0x00); | |
//Initialize SD Card | |
w = 0; | |
sMessage(F("Waiting for SD Card")); | |
while(!SD.begin(SD_CS)){ | |
//Serial.println(F("SD Card Error!")); | |
delayWithFlash(); | |
w++; | |
if (w >= MaxWait) { | |
sMessage(F("Waited too long, restarting.")); | |
delay(100); | |
reset(); | |
} | |
} | |
sMessage(F("SD Card Detected, finding first filename")); | |
// figure out first filename | |
sprintf(fnbuf, "%08d.jpg", filenum); | |
while(SD.exists(fnbuf)) | |
{ | |
filenum += 1000; | |
sprintf(fnbuf, "%08d.jpg", filenum); | |
} | |
sMessage(F("Setup complete!")); | |
digitalWrite(LED_BUILTIN, LOW); | |
} | |
void loop() { | |
char fnbuf[15]; | |
byte buf[256]; | |
static int i = 0; | |
int sleepCount = 2; | |
int s = 0; | |
uint8_t temp = 0,temp_last = 0; | |
uint32_t length = 0; | |
bool is_header = false; | |
File outFile; | |
// take a photo | |
sMessage(F("Waking camera and capturing...")); | |
myCAM.clear_bit(ARDUCHIP_GPIO, GPIO_PWDN_MASK); | |
delay(800); | |
//Flush the FIFO | |
myCAM.flush_fifo(); | |
//Clear the capture done flag | |
myCAM.clear_fifo_flag(); | |
//Start capture | |
myCAM.start_capture(); | |
// wait for capture | |
while(!myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK)); | |
sMessage(F("Capture complete")); | |
length = myCAM.read_fifo_length(); | |
if (length > 200000) | |
{ | |
// Large file, short sleep so we capture quickly | |
sleepCount = 3; | |
} | |
else | |
{ | |
// Small file, assume night time so sleep longer to save power | |
sleepCount = 200; | |
} | |
// Construct a file name | |
sprintf(fnbuf, "%08d.jpg", filenum); | |
//Open the new file | |
outFile = SD.open(fnbuf, O_WRITE | O_CREAT | O_TRUNC); | |
filenum++; | |
// copy image data to file | |
myCAM.CS_LOW(); | |
myCAM.set_fifo_burst(); | |
while ( length-- ) | |
{ | |
temp_last = temp; | |
temp = SPI.transfer(0x00); | |
//Read JPEG data from FIFO | |
if ( (temp == 0xD9) && (temp_last == 0xFF) ) //If find the end ,break while, | |
{ | |
buf[i++] = temp; //save the last 0XD9 | |
//Write the remain bytes in the buffer | |
myCAM.CS_HIGH(); | |
outFile.write(buf, i); | |
//Close the file | |
outFile.close(); | |
sMessage(F("Image Saved to SD")); | |
is_header = false; | |
i = 0; | |
} | |
if (is_header == true) | |
{ | |
//Write image data to buffer if not full | |
if (i < 256) | |
buf[i++] = temp; | |
else | |
{ | |
//Write 256 bytes image data to file | |
myCAM.CS_HIGH(); | |
outFile.write(buf, 256); | |
i = 0; | |
buf[i++] = temp; | |
myCAM.CS_LOW(); | |
myCAM.set_fifo_burst(); | |
} | |
} | |
else if ((temp == 0xD8) & (temp_last == 0xFF)) | |
{ | |
is_header = true; | |
buf[i++] = temp_last; | |
buf[i++] = temp; | |
} | |
} | |
// sleep for a while... | |
sMessage(F("Going to sleep...")); | |
myCAM.set_bit(ARDUCHIP_GPIO, GPIO_PWDN_MASK); | |
delay(1000); | |
for(s = 0; s < sleepCount; s++) | |
{ | |
// seems to be around 9 seconds per sleep | |
goToSleep(); | |
} | |
} | |
void sMessage(const __FlashStringHelper* m) { | |
#if defined USE_SERIAL | |
Serial.println(m); | |
#endif | |
} | |
void delayWithFlash() { | |
digitalWrite(LED_BUILTIN, LOW); | |
delay(500); | |
digitalWrite(LED_BUILTIN, HIGH); | |
delay(500); | |
} | |
void lowPowerSetup () { | |
// working from https://forum.arduino.cc/t/power-saving-techniques-on-a-stock-mega-2560/425563 | |
pinMode(A0, OUTPUT); | |
pinMode(A1, OUTPUT); | |
pinMode(A2, OUTPUT); | |
pinMode(A3, OUTPUT); | |
pinMode(A4, OUTPUT); | |
pinMode(A5, OUTPUT); | |
pinMode(A6, OUTPUT); | |
pinMode(A7, OUTPUT); | |
pinMode(A8, OUTPUT); | |
pinMode(A9, OUTPUT); | |
pinMode(A10, OUTPUT); | |
pinMode(A11, OUTPUT); | |
pinMode(A12, OUTPUT); | |
pinMode(A13, OUTPUT); | |
pinMode(A14, OUTPUT); | |
pinMode(A15, OUTPUT); | |
digitalWrite(A0, LOW); | |
digitalWrite(A1, LOW); | |
digitalWrite(A2, LOW); | |
digitalWrite(A3, LOW); | |
digitalWrite(A4, LOW); | |
digitalWrite(A5, LOW); | |
digitalWrite(A6, LOW); | |
digitalWrite(A7, LOW); | |
digitalWrite(A8, LOW); | |
digitalWrite(A9, LOW); | |
digitalWrite(A10, LOW); | |
digitalWrite(A11, LOW); | |
digitalWrite(A12, LOW); | |
digitalWrite(A13, LOW); | |
digitalWrite(A14, LOW); | |
digitalWrite(A15, LOW); | |
for (int i = 0; i <= 53; i++) { | |
if (i == CS) { continue; } | |
if (i == SD_CS) { continue; } | |
pinMode(i, OUTPUT); | |
digitalWrite(i, LOW); | |
} | |
power_adc_disable(); | |
//power_spi_disable(); | |
//power_usart0_disable(); | |
power_usart2_disable(); | |
power_timer1_disable(); | |
power_timer2_disable(); | |
power_timer3_disable(); | |
power_timer4_disable(); | |
power_timer5_disable(); | |
//power_twi_disable(); | |
} | |
void goToSleep() { | |
/*** Setup the Watch Dog Timer ***/ | |
/* Clear the reset flag. */ | |
MCUSR &= ~(1<<WDRF); | |
/* set new watchdog timeout prescaler value */ | |
WDTCSR |= (1<<WDCE) | (1<<WDE); | |
WDTCSR = 1<<WDP0 | 0<<WDP1 | 0<<WDP2 | 1<<WDP3; | |
WDTCSR |= _BV(WDIE); | |
set_sleep_mode(SLEEP_MODE_PWR_DOWN); | |
sleep_enable(); | |
sleep_mode(); | |
sleep_disable(); | |
} | |
ISR(WDT_vect) { | |
// Dummy watchdog timer handler to prevent reset | |
} | |
void reset() { asm volatile ("jmp 0"); } |
A few notes on the code. Near the top you can uncomment the line #define USE_SERIAL to get diagnostic messages written to the serial monitor. This can be useful for debugging if necessary. The sketch uses the built in LED to indicate problems as well - if everything is working you'll see the LED light up during setup and then switch off once the main loop starts. When a picture is written to the SD card the SD module LED will light up, so if you see that happening every 30 seconds or so then you should be in good shape. If the setup code fails to find the camera or SD module the internal LED will blink indicating that you need to fix something. Check that the OV5642 and SD modules are correctly wired. I would also try disconnecting power from the Mega for a few seconds. I have experienced connection issues with the OV5642 that are only fixed by a power cycle.
At startup there is also a check for existing files on the SD card and the file number is incremented by 1000 as needed until existing files will not be overwritten. This is useful in case the system loses power and restarts for any reason. I have included most configurable parameters for the camera module in the setup code like contrast and exposure adjustments so these should be easy to tweak based on your specific application.
Finally the startup code disables Mega features that are not used and after each photo the camera is powered down and the Mega put to sleep. Each sleep is around nine seconds. The number of sleeps depends on the size of the image - if below 200K it will sleep for around half an hour before trying again. This saves filling up the SD card with nighttime images and preserves power when the solar panel is unlikely to be helpful. This is another area to tweak depending on how you plan to use the system.
If you have any questions (or if you build this and it works for you) please leave a comment below.
(Published to the Fediverse as: Long term solar powered time lapse camera using Arduino #code #video #arduino #camera #c++ How to build and program a solar powered time lapse camera based on the Arduino Mega 2560 and a 5MP camera module. Includes full parts list and working code. )
South from Golden Gate Heights Park, a dead tree full of cormorants at Lake Merced, downtown and the Golden Gate from Grand View Park.
(Published to the Fediverse as: TLOTW #6 #timelapse #video #tlotw #goldengateheights #lakemerced #cormorant #grandview Timelapse of the week featuring views from Golden Gate Heights Park, Lake Merced and Grand View Park (all in San Francisco, California) )
Download a Sharepoint File with GraphServiceClient (Microsoft Graph API)
Accessing Printer Press ESC to cancel
Export Google Fit Daily Steps, Weight and Distance to a Google Sheet
Which PG&E rate plan works best for EV charging?
Monitor page index status with Google Sheets, Apps Script and the Google Search Console API
Bringing Sanity to Window Replacement in San Francisco
Enable GZIP compression for Amazon S3 hosted website in CloudFront