Ben's Blog

Category: maple syrup

47 Articles
maple syrup, self sustainability ben March 30, 2026

Boiling Quarters

I spent the whole week end in the sugar house, maple trees have been relentless this past week. We have ~5 gallons of syrup canned so far with at least 3 more coming. The smells are incredible in the Spring, Winter makes you forget that the world has any smell at all. Wet soil hits the hardest after a long Winter, and it’s quickly followed by pine smoke and sweet sap.

maple syrup, self sustainability ben March 01, 2026

Protected: Buckets are Up

This content is password-protected. To view it, please enter the password below.

maple syrup, self sustainability ben April 05, 2025

The Season is Done

Very smooth throughout. I’m not even sure how much we got, 10 gallons? More than enough for us and copious gifting. All we need to do is clean it all up now.

electronics, homestead automation, I.T., maple syrup, self sustainability ben March 15, 2025

Evaporator Regulator

This isn’t the most involved project but I might as well document it. I’ve been trying to automate some of the more boring tasks of running the evaporator, I’ve got some nice stainless steel float valves to regulate the sap going in now for example. One of the things that kept requiring constant attention is the air intake to adjust the strength of the fire. I’d have to sit with a foot on it to be able to regulate it almost constantly, to make sure the fire wasn’t burning too hard or too weak. And so naturally I thought I could do something with a Pi.

This proved quite successful even with very loose wiring and fastening just to see how it would work.

All of a sudden I barely need to pay attention to the fire’s strength, with a few refinements I won’t have to at all.

The circuit is quite simple:

Wifi barely reaches the sugarhouse so I made sure this could run independent of connectivity. Which involves coding threads on a Pi Pico, which is supported but not as one would expect.

import machine
import time
import network
import socket
from max6675 import MAX6675
import _thread
    

html = """{\"evaporator_temperature\":<TEMPERATURE>}"""

# LED
led = machine.Pin( "LED", machine.Pin.OUT )

# temperature
sck = machine.Pin( 2, machine.Pin.OUT )
cs = machine.Pin( 3, machine.Pin.OUT )
so = machine.Pin( 4, machine.Pin.IN )
sensor = MAX6675( sck, cs , so )
temperature_min = 25
temperature_max = 30
temperature = -1337.0

# servo
servo = machine.PWM( machine.Pin(0) )
servo.freq( 50 )
servo_min = 1000
servo_max = 8000
servo_at = 0


def temp_to_servo( temp ):
    if (temperature_max - temperature_min)==0:
        # right in the middle
        return int( (servo_max-servo_min)/2 )
    result = (temp - temperature_min) * (servo_max - servo_min) / (temperature_max - temperature_min) + servo_min
    if result>servo_max:
        result = servo_max
    if result<servo_min:
        result = servo_min
    return int( result )


def blink_number( number ):
    number = str( int(number) )
    for char in number:
        for i in range(int(char)):
            led.value( 1 )
            time.sleep( 0.2 )
            led.value( 0 )
            time.sleep( 0.2 )
        time.sleep( 0.3 )
        led.value( 1 )
        time.sleep( 0.1 )
        led.value( 0 )
        time.sleep( 0.3 )
            


keep_going = False
def servo_thread():
    global temperature, servo_at, servo
    
    while keep_going:
        time.sleep( 5 )
        print( "# measuring average temperature over 1 seconds..." )
        temperature_total = 0.0
        for i in range(10):
            temperature_total += sensor.read()
            time.sleep( 0.1 )
        temperature = temperature_total / 10
        blink_number( temperature )
        print( "# " + str(temperature) )
        new_servo_position = temp_to_servo( temperature )
        print( "# new_servo_position: " + str(new_servo_position) )
        step = 1
        if new_servo_position<servo_at:
            step = -1
        for i in range(servo_at, new_servo_position, step):
            time.sleep( 0.001 )
            servo_at = i
            servo.duty_u16( i )
    print( "# servo tread finishing" )

# main thread
servo.duty_u16( servo_min )
for i in range(servo_min, servo_max):
    time.sleep( 0.001 )
    servo_at = i
    servo.duty_u16( i )

try:
    ssid = "<wifi_ssid>"
    password = "<wifi_password>"
    wlan = network.WLAN( network.STA_IF )
    wlan.active( True )
    wlan.connect( ssid, password )

    # wait for connect or fail
    max_wait = 20
    while max_wait>0:
        if wlan.status() < 0 or wlan.status() >= 3:
            break
        max_wait -= 1
        print( "> waiting for connection..." )
        time.sleep( 1 )

    # handle connection error
    if wlan.status()!=3:
        print( "> network connection failed, will launch servo thread in 1 minute" )
        time.sleep( 60 )
        print( "> launching" )
        keep_going = True
        _thread.start_new_thread(servo_thread, ())
        while True:
            time.sleep( 1 )
    else:
        print( "> connected" )
        status = wlan.ifconfig()
        print( "ip = " + status[0] )

        # open socket
        addr = socket.getaddrinfo( "0.0.0.0", 80)[0][-1]
        s = socket.socket()
        s.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 )
        #s.settimeout(1)
        s.bind( addr )
        s.listen( 1 )
        print( "> web server listening on", addr )

        # listen for connections
        while True:
            print( ">" )
            try:
                cl, addr = s.accept()
                print( "client connected from", addr)

                request = cl.recv( 1024 )
               
                request = request.decode( "utf-8" ).strip()
                print( request )

                if request.startswith( "GET / " ):
                    print( "get data" )
                    response = html.replace( "<TEMPERATURE>", str(temperature) )
                    cl.send( "HTTP/1.0 200 OK\r\nContent-type: application/json\r\n\r\n" )
                    cl.send( response )
                elif request.startswith( "GET /min_temperature " ):
                     print( "get min_temperature" )
                     cl.send( "HTTP/1.0 200 OK\r\nContent-type: application/json\r\n\r\n" )
                     cl.send( str(temperature_min) )
                elif request.startswith( "GET /max_temperature " ):
                     print( "get max_temperature" )
                     cl.send( "HTTP/1.0 200 OK\r\nContent-type: application/json\r\n\r\n" )
                     cl.send( str(temperature_max) )
                elif request.startswith( "PUT /min_temperature " ):
                    print( "put min_temperature" )
                    new_min_temperature = int(request.split( "\r\n\r\n" )[1])
                    print( new_min_temperature )
                    temperature_min = new_min_temperature
                    cl.send( "HTTP/1.0 200 OK\r\nContent-type: application/json\r\n\r\n" )
                    cl.send( "\"ok\"" )
                elif request.startswith( "PUT /max_temperature " ):
                    print( "put max_temperature" )
                    new_max_temperature = int(request.split( "\r\n\r\n" )[1])
                    print( new_max_temperature )
                    temperature_max = new_max_temperature
                    cl.send( "HTTP/1.0 200 OK\r\nContent-type: application/json\r\n\r\n" )
                    cl.send( "\"ok\"" )
                elif request.startswith( "PUT /start " ):
                    print( "put start" )
                    cl.send( "HTTP/1.0 200 OK\r\nContent-type: application/json\r\n\r\n" )
                    if keep_going:
                        print( "  already started" )
                        cl.send( "\"already started\"" )
                    else:
                        keep_going = True
                        _thread.start_new_thread(servo_thread, ())
                        cl.send( "\"started\"" )
                        for i in range(5000, 6000):
                            time.sleep( 0.001 )
                            servo_at = i
                            servo.duty_u16( i )
                elif request.startswith( "PUT /stop " ):
                    print( "put stop" )
                    #cl.send( "HTTP/1.0 501 OK\r\nContent-type: application/json\r\n\r\n" )
                    #cl.send( "\"not implemented\"" )
                    # crash on stop, thread support is that bad
                    cl.send( "HTTP/1.0 200 OK\r\nContent-type: application/json\r\n\r\n" )
                    if keep_going:
                        keep_going = False
                        cl.send( "\"stopped\"" )
                    else:
                        print( "  already stopped" )
                        cl.send( "\"already stopped\"" )

                cl.close()
         
            except OSError as e:
                cl.close()
                print( "> connection closed" )
                keep_going = False
                time.sleep( 2 )
    

except KeyboardInterrupt:
    print( "> ctrl+c, wrapping up..." )
    keep_going = False
    time.sleep( 10 )
except Exception as e:
    print( e )
    print( "> unexpected exception, wrapping up..." )
    keep_going = False
    time.sleep( 10 )

import time
class MAX6675:
    MEASUREMENT_PERIOD_MS = 220

    def __init__(self, sck, cs, so):
        """
        Creates new object for controlling MAX6675
        :param sck: SCK (clock) pin, must be configured as Pin.OUT
        :param cs: CS (select) pin, must be configured as Pin.OUT
        :param so: SO (data) pin, must be configured as Pin.IN
        """
        # Thermocouple
        self._sck = sck
        self._sck.low()

        self._cs = cs
        self._cs.high()

        self._so = so
        self._so.low()

        self._last_measurement_start = 0
        self._last_read_temp = 0
        self._error = 0

    def _cycle_sck(self):
        self._sck.high()
        time.sleep_us(1)
        self._sck.low()
        time.sleep_us(1)

    def refresh(self):
        """
        Start a new measurement.
        """
        self._cs.low()
        time.sleep_us(10)
        self._cs.high()
        self._last_measurement_start = time.ticks_ms()

    def ready(self):
        """
        Signals if measurement is finished.
        :return: True if measurement is ready for reading.
        """
        return time.ticks_ms() - self._last_measurement_start > MAX6675.MEASUREMENT_PERIOD_MS

    def error(self):
        """
        Returns error bit of last reading. If this bit is set (=1), there's problem with the
        thermocouple - it can be damaged or loosely connected
        :return: Error bit value
        """
        return self._error

    def read(self):
        """
        Reads last measurement and starts a new one. If new measurement is not ready yet, returns last value.
        Note: The last measurement can be quite old (e.g. since last call to `read`).
        To refresh measurement, call `refresh` and wait for `ready` to become True before reading.
        :return: Measured temperature
        """
        # Check if new reading is available
        if self.ready():
            # Bring CS pin low to start protocol for reading result of
            # the conversion process. Forcing the pin down outputs
            # first (dummy) sign bit 15.
            self._cs.low()
            time.sleep_us(10)

            # Read temperature bits 14-3 from MAX6675.
            value = 0
            for i in range(12):
                # SCK should resemble clock signal and new SO value
                # is presented at falling edge
                self._cycle_sck()
                value += self._so.value() << (11 - i)

            # Read the TC Input pin to check if the input is open
            self._cycle_sck()
            self._error = self._so.value()

            # Read the last two bits to complete protocol
            for i in range(2):
                self._cycle_sck()

            # Finish protocol and start new measurement
            self._cs.high()
            self._last_measurement_start = time.ticks_ms()

            self._last_read_temp = value * 0.25

        return self._last_read_temp

Web requests collection.

maple syrup, self sustainability ben March 15, 2025

We’re Boiling

The operations is smoother, the kids are older. Sugaring season is liminal time between Winter and Spring sitting by the evaporator for hours on end. Often prompting discussions we wouldn’t otherwise have. I love this time of the year very much.

Now this Winter has been more more “normal” for Vermont, and sugaring season started the week after Town Meeting day which is tradition I hear, but not anything we’re used to. Sap hit hard these past few days and we had to start boiling it off fast to make room for more.

maple syrup, self sustainability ben March 04, 2025

Protected: It’s Cold

This content is password-protected. To view it, please enter the password below.

maple syrup, self sustainability ben March 30, 2024

Protected: It’s the Season of Mistakes

This content is password-protected. To view it, please enter the password below.

maple syrup, self sustainability ben March 23, 2024

Birch Syrup

One of the maple taps wasn’t producing much at all, so I moved it to a birch tree. I had tried before but was too late and didn’t really get anything. This time though, the sap was flowing and so I got about a gallon that I boiled on the stove inside.

And it was really delicious. Much like maple syrup but with more of a floral tone. Maple syrup takes ~40 gallons of sap to get 1 gallon of syrup, a 40:1 ratio on average. Birch syrup is 100:1! That explains why it’s not common. I’m definitely curious about it though. In one season, we make enough Maple syrup for our family’s generous use for a good 2 years. Maybe I could do Birch every other year. It’s the same process with the same tools, just more water boiled out.

maple syrup, self sustainability ben March 15, 2024

Finally

After last year’s hiatus, we’re back into sugaring. It’s a whole lot of work, but it’s also very rewarding and I love doing it. I love that everyone around us is involved in it somehow, it’s got a community wide feeling to it.

The contemplative boil coupled with the smell are the parts I was missing the most.

When we wind down the operation, I don’t need to feed the fire every 5 minutes. The fire bricks keep plenty of heat to keep evaporating several gallons for an hour or 2, so I keep an eye on things remotely.

When we draw syrup, I don’t take pictures. There’s too much going on and it gets very sticky. Between the bucket collection, the boiling, the draws, the cleanups, moving wood, it’s really a lot of work. We were insane to do it outside through the night and moving sap by hand a few years back. I have a distinct memory of being outside by myself at 2AM, seeing light in my warm house from a distance, hearing coyotes come down the hill, and really wondering what the fuck I was doing there. And I would always worry that a bear would knock down the pan to get in the syrup. I’m glad I don’t have to do this anymore, but I’m also glad I did it.

I’m bubbling with ideas for things I want to improve in the operation.

maple syrup, self sustainability ben February 22, 2024

Protected: Buckets are Up

This content is password-protected. To view it, please enter the password below.

maple syrup, self sustainability ben February 20, 2024

Scrub scrub

Cleaning up everything to get ready for 2024’s sugaring season, which seems to be a bit later than the mid-february start we’ve gotten used to.

Flue scrub

Tank scrub

maple syrup, self sustainability ben April 10, 2022

9 Gallons

That’s the verdict for Sugaring 2022. I’ve heard that the sugar content in the sap wasn’t very high this year, and I believe it. I was surprised at how little syrup we got for how much we boiled. Another thing we’ve been told is that the later sap runs were “buddy”, meaning that the taste is a bit off from the trees budding. Except they weren’t actually budding so that is this year’s peculiarity. Nothing to complain about though, it’s been a good year.

maple syrup, self sustainability ben March 28, 2022

Protected: Sugaring Week End

This content is password-protected. To view it, please enter the password below.

maple syrup, miscellaneous ben March 28, 2022

Protected: Beer Me

This content is password-protected. To view it, please enter the password below.

maple syrup, self sustainability ben March 23, 2022

Protected: Shaping Up to be a Good Year

This content is password-protected. To view it, please enter the password below.

maple syrup, self sustainability ben March 14, 2022

Cozy Boiling Spot

Wifi now reaches in the Sugarhouse.

maple syrup, self sustainability ben March 06, 2022

Protected: Let the Tree Bleeding Commence

This content is password-protected. To view it, please enter the password below.

maple syrup, self sustainability ben April 16, 2021

Not the best sap year

We only had 1 good week of sap flow this year, and only boiled 1 batch. It just wasn’t a maple syrup year. We still made 5 gallons which is enough for our family’s yearly consumption, and we still have 2 gallons left from last year. We’ve been experimenting with making granulated sugar with it. Last year we tried maple candy, and that was delicious but it was a lot of work. Granulated is much easier to make and to substitute in recipes. We will try to ramp up our sap production next year.

It’s cleanup time.

 

The loot

maple syrup, self sustainability ben March 22, 2021

Protected: We’re boiling

This content is password-protected. To view it, please enter the password below.

maple syrup, self sustainability ben March 14, 2021

Not a Banner Year thus far

Very little flow and we’re already mid March.

maple syrup, self sustainability ben February 16, 2021

Creating Sugaring Paths

Sugaring season is around the corner and so I’m giving us paths through the woods. No sledding 35 gallons of sap, no stuck ATVs. One hard lesson after another, we now know what to do and when. We also know how: I didn’t even get the tractor stuck and made quick work of it all. It’s so nice for these things to have become evident.

maple syrup, self sustainability ben April 02, 2020

Protected: Maple Juice 2020 wrapping up

This content is password-protected. To view it, please enter the password below.

maple syrup, self sustainability ben March 09, 2020

Protected: Grand Opening

This content is password-protected. To view it, please enter the password below.

Posts pagination

1 2 3 Next →

This blog is solar powered

Interactive

Handwriting Capture
Mandalagaba
IPv6 link-local to MAC converter
IPv6 MAC to link-local converter
Markov Text Generation
Markov Word Generation
Markov Music Generation
Duplogrifier
Flood Fill Algorithms
Homestead Metrics
RGB Playground
Web Games

Categories

  • aesthetics111
    • plots54
    • specular holography6
  • Books3
  • I.T.202
    • 3D modeling / printing21
    • AI6
    • all out geekery36
    • electronics27
    • homestead automation6
    • maniacal paranoia25
    • plotters49
    • unix / linux29
    • video games4
    • web development29
    • web games3
  • Lego / Duplo67
  • life in the U.S.42
  • miscellaneous202
  • nature encounters114
  • old vinyls3
  • organs2
  • self sustainability560
    • agriculture105
    • apiculture38
    • apple20
    • building131
    • canning3
    • crochet6
    • foraging6
    • hunting10
    • maple syrup47
    • poultry39
    • preserving2
    • solar power28
    • water23
    • wood84
  • trip to a new life6
Theme by Bloompixel. Proudly Powered by WordPress