maple syrup – Ben's Blog https://ben.akrin.com Mon, 30 Mar 2026 02:43:11 +0000 en-US hourly 1 https://wordpress.org/?v=7.1 Boiling Quarters https://ben.akrin.com/boiling-quarters/ https://ben.akrin.com/boiling-quarters/#respond Mon, 30 Mar 2026 02:43:11 +0000 https://ben.akrin.com/?p=14441 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.

]]>
https://ben.akrin.com/boiling-quarters/feed/ 0
Protected: Buckets are Up https://ben.akrin.com/buckets-are-up-2/ https://ben.akrin.com/buckets-are-up-2/#respond Sun, 01 Mar 2026 02:23:58 +0000 https://ben.akrin.com/?p=14381

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

]]>
https://ben.akrin.com/buckets-are-up-2/feed/ 0
The Season is Done https://ben.akrin.com/the-season-is-done/ https://ben.akrin.com/the-season-is-done/#respond Sat, 05 Apr 2025 02:44:48 +0000 https://ben.akrin.com/?p=13397 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.

]]>
https://ben.akrin.com/the-season-is-done/feed/ 0
Evaporator Regulator https://ben.akrin.com/evaporator-regulator/ https://ben.akrin.com/evaporator-regulator/#respond Sat, 15 Mar 2025 22:01:23 +0000 https://ben.akrin.com/?p=13131 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.

]]>
https://ben.akrin.com/evaporator-regulator/feed/ 0
We’re Boiling https://ben.akrin.com/were-boiling-2/ https://ben.akrin.com/were-boiling-2/#respond Sat, 15 Mar 2025 21:37:22 +0000 https://ben.akrin.com/?p=13345 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.

]]>
https://ben.akrin.com/were-boiling-2/feed/ 0
Protected: It’s Cold https://ben.akrin.com/its-cold/ https://ben.akrin.com/its-cold/#respond Tue, 04 Mar 2025 15:16:24 +0000 https://ben.akrin.com/?p=13314

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

]]>
https://ben.akrin.com/its-cold/feed/ 0
Protected: It’s the Season of Mistakes https://ben.akrin.com/its-the-season-of-mistakes/ https://ben.akrin.com/its-the-season-of-mistakes/#respond Sat, 30 Mar 2024 06:58:03 +0000 https://ben.akrin.com/?p=12794

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

]]>
https://ben.akrin.com/its-the-season-of-mistakes/feed/ 0
Birch Syrup https://ben.akrin.com/birch-syrup/ https://ben.akrin.com/birch-syrup/#respond Sat, 23 Mar 2024 13:28:44 +0000 https://ben.akrin.com/?p=12725 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.

]]>
https://ben.akrin.com/birch-syrup/feed/ 0
Finally https://ben.akrin.com/finally/ https://ben.akrin.com/finally/#respond Fri, 15 Mar 2024 03:32:55 +0000 https://ben.akrin.com/?p=12730 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.

]]>
https://ben.akrin.com/finally/feed/ 0
Protected: Buckets are Up https://ben.akrin.com/buckets-are-up/ https://ben.akrin.com/buckets-are-up/#respond Thu, 22 Feb 2024 01:37:33 +0000 https://ben.akrin.com/?p=12620

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

]]>
https://ben.akrin.com/buckets-are-up/feed/ 0
Scrub scrub https://ben.akrin.com/scrub-scrub/ https://ben.akrin.com/scrub-scrub/#respond Tue, 20 Feb 2024 22:24:44 +0000 https://ben.akrin.com/?p=12613 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

]]>
https://ben.akrin.com/scrub-scrub/feed/ 0
9 Gallons https://ben.akrin.com/9-gallons/ https://ben.akrin.com/9-gallons/#respond Sun, 10 Apr 2022 02:00:44 +0000 https://ben.akrin.com/?p=11164 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.

]]>
https://ben.akrin.com/9-gallons/feed/ 0
Protected: Sugaring Week End https://ben.akrin.com/sugaring-week-end/ https://ben.akrin.com/sugaring-week-end/#respond Mon, 28 Mar 2022 02:29:29 +0000 https://ben.akrin.com/?p=11113

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

]]>
https://ben.akrin.com/sugaring-week-end/feed/ 0
Protected: Beer Me https://ben.akrin.com/beer-me/ https://ben.akrin.com/beer-me/#respond Mon, 28 Mar 2022 01:22:48 +0000 https://ben.akrin.com/?p=11117

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

]]>
https://ben.akrin.com/beer-me/feed/ 0
Protected: Shaping Up to be a Good Year https://ben.akrin.com/shaping-up-to-be-a-good-year/ https://ben.akrin.com/shaping-up-to-be-a-good-year/#respond Wed, 23 Mar 2022 02:15:48 +0000 https://ben.akrin.com/?p=11063

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

]]>
https://ben.akrin.com/shaping-up-to-be-a-good-year/feed/ 0
Cozy Boiling Spot https://ben.akrin.com/cozy-boiling-spot/ https://ben.akrin.com/cozy-boiling-spot/#respond Mon, 14 Mar 2022 03:02:00 +0000 https://ben.akrin.com/?p=11053 Wifi now reaches in the Sugarhouse.

]]>
https://ben.akrin.com/cozy-boiling-spot/feed/ 0
Protected: Let the Tree Bleeding Commence https://ben.akrin.com/let-the-tree-bleeding-commence/ https://ben.akrin.com/let-the-tree-bleeding-commence/#respond Sun, 06 Mar 2022 02:51:43 +0000 https://ben.akrin.com/?p=11044

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

]]>
https://ben.akrin.com/let-the-tree-bleeding-commence/feed/ 0
Not the best sap year https://ben.akrin.com/not-the-best-sap-year/ https://ben.akrin.com/not-the-best-sap-year/#respond Fri, 16 Apr 2021 11:38:23 +0000 https://ben.akrin.com/?p=10269 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

]]>
https://ben.akrin.com/not-the-best-sap-year/feed/ 0
Protected: We’re boiling https://ben.akrin.com/were-boiling/ https://ben.akrin.com/were-boiling/#respond Mon, 22 Mar 2021 01:56:26 +0000 https://ben.akrin.com/?p=10246

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

]]>
https://ben.akrin.com/were-boiling/feed/ 0
Not a Banner Year thus far https://ben.akrin.com/not-a-banner-year-thus-far/ https://ben.akrin.com/not-a-banner-year-thus-far/#respond Sun, 14 Mar 2021 03:41:10 +0000 https://ben.akrin.com/?p=10239 Very little flow and we’re already mid March.

]]>
https://ben.akrin.com/not-a-banner-year-thus-far/feed/ 0
Creating Sugaring Paths https://ben.akrin.com/creating-sugaring-paths/ https://ben.akrin.com/creating-sugaring-paths/#respond Tue, 16 Feb 2021 02:51:11 +0000 https://ben.akrin.com/?p=10191 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.

]]>
https://ben.akrin.com/creating-sugaring-paths/feed/ 0
Protected: Maple Juice 2020 wrapping up https://ben.akrin.com/maple-juice-2020-wrapping-up/ https://ben.akrin.com/maple-juice-2020-wrapping-up/#respond Thu, 02 Apr 2020 02:53:29 +0000 https://ben.akrin.com/?p=9260

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

]]>
https://ben.akrin.com/maple-juice-2020-wrapping-up/feed/ 0
Protected: Grand Opening https://ben.akrin.com/grand-opening/ https://ben.akrin.com/grand-opening/#respond Mon, 09 Mar 2020 21:46:31 +0000 https://ben.akrin.com/?p=9227

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

]]>
https://ben.akrin.com/grand-opening/feed/ 0