There are two main options here: dependency injection or mocking. Dependency injection in your case would mean that the program would take a reference to the source of temperature data, which you can then fake in order to check that the code is doing the right thing at the interface to the temperature source. Alternatively you can mock the source of temperature data by basically replacing the source of the temperature data with a convenient set of numbers.
Dependency injection is the preferred method, since it makes it obvious which external sources of data your program depends on. Mocking is easier with legacy code, but tends to make your tests hard to follow — mocking is effectively interpreter or compiler magic — and brittle, since your tests now depend on (lower level than DI) implementation details.
Example of code where you can test with "current" time to your heart's content:
from typing import Callable
def something_with_time(clock: Callable[, datetime.datetime]) -> None:
now = clock()
As you can see that is easily unit tested — test code will pass a function returning whatever you want (including exactly midnight, timezone transitions, leap seconds, etc.), and production code will pass a function like
datetime.datetime.now. Mocking with legacy code example:
from unittest import mock
now = datetime.datetime.now()
@mock.patch('datetime.datetime.now', [datetime.datetime(2000, 1, 1), datetime.datetime(2000, 1, 2)])
def test_should_something_something(self) -> None: