<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>programming - Hard Wired</title>
	<atom:link href="https://www.hardwired.dev/tag/programming/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.hardwired.dev</link>
	<description></description>
	<lastBuildDate>Sat, 11 Apr 2026 16:09:02 +0000</lastBuildDate>
	<language>cs</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://www.hardwired.dev/wp-content/uploads/2022/10/android-chrome-256x256-1-150x150.png</url>
	<title>programming - Hard Wired</title>
	<link>https://www.hardwired.dev</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Multimodal Embedding &#038; Reranker Models with Sentence Transformers</title>
		<link>https://www.hardwired.dev/2026/04/10/multimodal-embedding-reranker-models-with-sentence-transformers/</link>
		
		<dc:creator><![CDATA[Yukiko Hesse]]></dc:creator>
		<pubDate>Fri, 10 Apr 2026 20:32:42 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[artificial intelligence]]></category>
		<category><![CDATA[computer vision]]></category>
		<category><![CDATA[cross-modal search]]></category>
		<category><![CDATA[embedding models]]></category>
		<category><![CDATA[image retrieval]]></category>
		<category><![CDATA[machine learning]]></category>
		<category><![CDATA[multimodal models]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[RAG]]></category>
		<category><![CDATA[reranker]]></category>
		<category><![CDATA[Semantic search]]></category>
		<category><![CDATA[sentence transformers]]></category>
		<guid isPermaLink="false">https://www.hardwired.dev/?p=3030</guid>

					<description><![CDATA[<p>Multimodal Embedding &#38; Reranker Models with Sentence Transformers Sentence Transformers is a Python library for using and training embedding and &#62;&#62;&#62;</p>
<p>The post <a href="https://www.hardwired.dev/2026/04/10/multimodal-embedding-reranker-models-with-sentence-transformers/">Multimodal Embedding & Reranker Models with Sentence Transformers</a> first appeared on <a href="https://www.hardwired.dev">Hard Wired</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><h1>Multimodal Embedding &amp; Reranker Models with Sentence Transformers</h1>
<p>Sentence Transformers is a Python library for using and training embedding and reranker models for applications like retrieval augmented generation, semantic search, and more. With the v5.4 update, you can now encode and compare texts, images, audio, and videos using the same familiar API. In this blogpost, I'll show you how to use these new multimodal capabilities for both embedding and reranking.</p>
</p>
<p>Multimodal embedding models map inputs from different modalities into a shared embedding space, while multimodal reranker models score the relevance of mixed-modality pairs. This opens up use cases like visual document retrieval, cross-modal search, and multimodal RAG pipelines.</p>
<h2>Table of Contents</h2>
<ul>
<li><a href="#what-are-multimodal-models">What are Multimodal Models?</a></li>
<li><a href="#installation">Installation</a></li>
<li><a href="#multimodal-embedding-models">Multimodal Embedding Models</a></li>
<li><a href="#loading-a-model">Loading a Model</a></li>
<li><a href="#encoding-images">Encoding Images</a></li>
<li><a href="#cross-modal-similarity">Cross-Modal Similarity</a></li>
<li><a href="#encoding-queries-and-documents">Encoding Queries and Documents</a></li>
<li><a href="#multimodal-reranker-models">Multimodal Reranker Models</a></li>
<li><a href="#ranking-mixed-modality-documents">Ranking Mixed-Modality Documents</a></li>
<li><a href="#predicting-pair-scores">Predicting Pair Scores</a></li>
<li><a href="#retrieve-and-rerank">Retrieve and Rerank</a></li>
<li><a href="#input-formats-and-configuration">Input Formats and Configuration</a></li>
<li><a href="#supported-input-types">Supported Input Types</a></li>
<li><a href="#checking-modality-support">Checking Modality Support</a></li>
<li><a href="#processor-and-model-kwargs">Processor and Model kwargs</a></li>
<li><a href="#supported-models">Supported Models</a></li>
<li><a href="#additional-resources">Additional Resources</a></li>
</ul>
<h2>What are Multimodal Models?</h2>
<p>Traditional embedding models convert text into fixed-size vectors. Multimodal embedding models extend this by mapping inputs from different modalities (text, images, audio, or video) into a shared embedding space. This means you can compare a text query against image documents (or vice versa) using the same similarity functions you're already familiar with.</p>
<p>Similarly, traditional reranker (Cross Encoder) models compute relevance scores between pairs of texts. Multimodal rerankers can score pairs where one or both elements are images, combined text-image documents, or other modalities.</p>
<p>For example, you can compare a text query against image documents, find video clips matching a description, or build RAG pipelines that work across modalities.</p>
<h2>Installation</h2>
<p>Multimodal models require some extra dependencies. Install the extras for the modalities you need (see <a href="https://sbert.net/docs/installation.html">Installation</a> for more details):</p>
<div class="codehilite">
<pre><span></span><code><span class="c1"># For image support</span>
pip<span class="w"> </span>install<span class="w"> </span>-U<span class="w"> </span><span class="s2">&quot;sentence-transformers[image]&quot;</span>

<span class="c1"># For audio support</span>
pip<span class="w"> </span>install<span class="w"> </span>-U<span class="w"> </span><span class="s2">&quot;sentence-transformers&quot;</span>

<span class="c1"># For video support</span>
pip<span class="w"> </span>install<span class="w"> </span>-U<span class="w"> </span><span class="s2">&quot;sentence-transformers&quot;</span>

<span class="c1"># Mix and match as needed</span>
pip<span class="w"> </span>install<span class="w"> </span>-U<span class="w"> </span><span class="s2">&quot;sentence-transformers[image,video,train]&quot;</span>
</code></pre>
</div>
<p>VLM-based models like Qwen3-VL-2B require a GPU with at least ~8 GB of VRAM. For the 8B variants, expect ~20 GB. If you don't have a local GPU, consider using a cloud GPU service or Google Colab. On CPU, these models will be extremely slow; text-only or CLIP models are better suited for CPU inference.</p>
<h2>Multimodal Embedding Models</h2>
<h3>Loading a Model</h3>
<p>Loading a multimodal embedding model works exactly like loading a text-only model:</p>
<div class="codehilite">
<pre><span></span><code><span class="kn">from</span> <span class="nn">sentence_transformers</span> <span class="kn">import</span> <span class="n">SentenceTransformer</span>

<span class="n">model</span> <span class="o">=</span> <span class="n">SentenceTransformer</span><span class="p">(</span><span class="s2">&quot;Qwen/Qwen3-VL-Embedding-2B&quot;</span><span class="p">,</span> <span class="n">revision</span><span class="o">=</span><span class="s2">&quot;refs/pr/23&quot;</span><span class="p">)</span>
</code></pre>
</div>
<p>The revision argument is required for now because the integration pull requests for these models are still pending. Once they're merged, you'll be able to load them without specifying a revision.</p>
<p>The model automatically detects which modalities it supports, so there's nothing extra to configure. See <a href="#processor-and-model-kwargs">Processor and Model kwargs</a> if you want to control things like image resolution or model precision.</p>
<h3>Encoding Images</h3>
<p>With a multimodal model loaded, <code>model.encode()</code> accepts images alongside text. Images can be provided as URLs, local file paths, or PIL Image objects (see <a href="#supported-input-types">Supported Input Types</a> for all accepted formats):</p>
<div class="codehilite">
<pre><span></span><code><span class="kn">from</span> <span class="nn">sentence_transformers</span> <span class="kn">import</span> <span class="n">SentenceTransformer</span>

<span class="n">model</span> <span class="o">=</span> <span class="n">SentenceTransformer</span><span class="p">(</span><span class="s2">&quot;Qwen/Qwen3-VL-Embedding-2B&quot;</span><span class="p">,</span> <span class="n">revision</span><span class="o">=</span><span class="s2">&quot;refs/pr/23&quot;</span><span class="p">)</span>

<span class="c1"># Encode images from URLs</span>
<span class="n">img_embeddings</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">encode</span><span class="p">([</span>
 <span class="s2">&quot;https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/car.jpg&quot;</span><span class="p">,</span>
 <span class="s2">&quot;https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg&quot;</span><span class="p">,</span>
<span class="p">])</span>
<span class="nb">print</span><span class="p">(</span><span class="n">img_embeddings</span><span class="o">.</span><span class="n">shape</span><span class="p">)</span>
<span class="c1"># (2, 2048)</span>
</code></pre>
</div>
<h3>Cross-Modal Similarity</h3>
<p>You can compute similarities between text embeddings and image embeddings, since the model maps both into the same space:</p>
<div class="codehilite">
<pre><span></span><code><span class="kn">from</span> <span class="nn">sentence_transformers</span> <span class="kn">import</span> <span class="n">SentenceTransformer</span>

<span class="n">model</span> <span class="o">=</span> <span class="n">SentenceTransformer</span><span class="p">(</span><span class="s2">&quot;Qwen/Qwen3-VL-Embedding-2B&quot;</span><span class="p">,</span> <span class="n">revision</span><span class="o">=</span><span class="s2">&quot;refs/pr/23&quot;</span><span class="p">)</span>

<span class="c1"># Encode images</span>
<span class="n">img_embeddings</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">encode</span><span class="p">([</span>
 <span class="s2">&quot;https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/car.jpg&quot;</span><span class="p">,</span>
 <span class="s2">&quot;https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg&quot;</span><span class="p">,</span>
<span class="p">])</span>

<span class="c1"># Encode text queries (one matching + one hard negative per image)</span>
<span class="n">text_embeddings</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">encode</span><span class="p">([</span>
 <span class="s2">&quot;A green car parked in front of a yellow building&quot;</span><span class="p">,</span>
 <span class="s2">&quot;A red car driving on a highway&quot;</span><span class="p">,</span>
 <span class="s2">&quot;A bee on a pink flower&quot;</span><span class="p">,</span>
 <span class="s2">&quot;A wasp on a wooden table&quot;</span><span class="p">,</span>
<span class="p">])</span>

<span class="c1"># Compute cross-modal similarities</span>
<span class="n">similarities</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">similarity</span><span class="p">(</span><span class="n">text_embeddings</span><span class="p">,</span> <span class="n">img_embeddings</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">similarities</span><span class="p">)</span>
<span class="c1"># tensor([[0.5115, 0.1078],</span>
<span class="c1"># [0.1999, 0.1108],</span>
<span class="c1"># [0.1255, 0.6749],</span>
<span class="c1"># [0.1283, 0.2704]])</span>
</code></pre>
</div>
<p>As expected, "A green car parked in front of a yellow building" is most similar to the car image (0.51), and "A bee on a pink flower" is most similar to the bee image (0.67). The hard negatives ("A red car driving on a highway", "A wasp on a wooden table") correctly receive lower scores.</p>
<p>You might notice that even the best matching scores (0.51, 0.67) aren't very close to 1.0. This is due to the <a href="https://arxiv.org/abs/2203.02053">modality gap</a>: embeddings from different modalities tend to cluster in separate regions of the space. Cross-modal similarities are typically lower than within-modal ones (e.g., text-to-text), but the relative ordering is preserved, so retrieval still works well.</p>
<h3>Encoding Queries and Documents</h3>
<p>For retrieval tasks, <code>encode_query()</code> and <code>encode_document()</code> are the recommended methods. Many retrieval models prepend different instruction prompts depending on whether the input is a query or a document, similar to how chat models might apply different system prompts depending on the goal. Model authors can specify their prompts in the model config, and <code>encode_query()</code> / <code>encode_document()</code> automatically load and apply the correct one:</p>
<ul>
<li><code>encode_query()</code> uses the model's "query" prompt (if available) and sets <code>task="query"</code>.</li>
<li><code>encode_document()</code> uses the first available prompt from "document", "passage", or "corpus", and sets <code>task="document"</code>.</li>
</ul>
<p>Under the hood, both are thin wrappers around <code>encode()</code>, they just handle prompt selection for you. Here's what cross-modal retrieval looks like:</p>
<div class="codehilite">
<pre><span></span><code><span class="kn">from</span> <span class="nn">sentence_transformers</span> <span class="kn">import</span> <span class="n">SentenceTransformer</span>

<span class="n">model</span> <span class="o">=</span> <span class="n">SentenceTransformer</span><span class="p">(</span><span class="s2">&quot;Qwen/Qwen3-VL-Embedding-2B&quot;</span><span class="p">,</span> <span class="n">revision</span><span class="o">=</span><span class="s2">&quot;refs/pr/23&quot;</span><span class="p">)</span>

<span class="c1"># Encode text queries with the query prompt</span>
<span class="n">query_embeddings</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">encode_query</span><span class="p">([</span>
 <span class="s2">&quot;Find me a photo of a vehicle parked near a building&quot;</span><span class="p">,</span>
 <span class="s2">&quot;Show me an image of a pollinating insect&quot;</span><span class="p">,</span>
<span class="p">])</span>

<span class="c1"># Encode document screenshots with the document prompt</span>
<span class="n">doc_embeddings</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">encode_document</span><span class="p">([</span>
 <span class="s2">&quot;https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/car.jpg&quot;</span><span class="p">,</span>
 <span class="s2">&quot;https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg&quot;</span><span class="p">,</span>
<span class="p">])</span>

<span class="c1"># Compute similarities</span>
<span class="n">similarities</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">similarity</span><span class="p">(</span><span class="n">query_embeddings</span><span class="p">,</span> <span class="n">doc_embeddings</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">similarities</span><span class="p">)</span>
<span class="c1"># tensor([[0.3907, 0.1490],</span>
<span class="c1"># [0.1235, 0.4872]])</span>
</code></pre>
</div>
<p>These methods accept the same input types as <code>encode()</code> (images, URLs, multimodal dicts, etc.) and pass through the same parameters. For models without specialized query/document prompts, they behave identically to <code>encode()</code>.</p>
<h2>Multimodal Reranker Models</h2>
<p>Multimodal reranker (CrossEncoder) models score the relevance between pairs of inputs, where each element can be text, an image, audio, video, or a combination. They tend to outperform embedding models in terms of quality, but are slower since they process each pair individually. The currently available pretrained multimodal rerankers focus on text and image inputs, but the architecture supports any modality that the underlying model can handle.</p>
<h3>Ranking Mixed-Modality Documents</h3>
<p>The <code>rank()</code> method scores and ranks a list of documents against a query, supporting mixed modalities:</p>
<div class="codehilite">
<pre><span></span><code><span class="kn">from</span> <span class="nn">sentence_transformers</span> <span class="kn">import</span> <span class="n">CrossEncoder</span>

<span class="n">model</span> <span class="o">=</span> <span class="n">CrossEncoder</span><span class="p">(</span><span class="s2">&quot;Qwen/Qwen3-VL-Reranker-2B&quot;</span><span class="p">,</span> <span class="n">revision</span><span class="o">=</span><span class="s2">&quot;refs/pr/11&quot;</span><span class="p">)</span>

<span class="n">query</span> <span class="o">=</span> <span class="s2">&quot;A green car parked in front of a yellow building&quot;</span>
<span class="n">documents</span> <span class="o">=</span> <span class="p">[</span>
 <span class="c1"># Image documents (URL or local file path)</span>
 <span class="s2">&quot;https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/car.jpg&quot;</span><span class="p">,</span>
 <span class="s2">&quot;https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg&quot;</span><span class="p">,</span>
 <span class="c1"># Text document</span>
 <span class="s2">&quot;A vintage Volkswagen Beetle painted in bright green sits in a driveway.&quot;</span><span class="p">,</span>
 <span class="c1"># Combined text + image document</span>
 <span class="p">{</span>
 <span class="s2">&quot;text&quot;</span><span class="p">:</span> <span class="s2">&quot;A car in a European city&quot;</span><span class="p">,</span>
 <span class="s2">&quot;image&quot;</span><span class="p">:</span> <span class="s2">&quot;https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/car.jpg&quot;</span><span class="p">,</span>
 <span class="p">},</span>
<span class="p">]</span>

<span class="n">rankings</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">rank</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">documents</span><span class="p">)</span>
<span class="k">for</span> <span class="n">rank</span> <span class="ow">in</span> <span class="n">rankings</span><span class="p">:</span>
 <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">rank</span><span class="p">[</span><span class="s1">&#39;score&#39;</span><span class="p">]</span><span class="si">:</span><span class="s2">.4f</span><span class="si">}</span><span class="se">\t</span><span class="s2">(document </span><span class="si">{</span><span class="n">rank</span><span class="p">[</span><span class="s1">&#39;corpus_id&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">)&quot;</span><span class="p">)</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd">0.9375 (document 0)</span>
<span class="sd">0.5000 (document 3)</span>
<span class="sd">-1.2500 (document 2)</span>
<span class="sd">-2.4375 (document 1)</span>
<span class="sd">&quot;&quot;&quot;</span>
</code></pre>
</div>
<p>The reranker correctly identifies the car image (document 0) as the most relevant result, followed by the combined text+image document about a car in a European city (document 3). The bee image (document 1) scores lowest.</p>
<p>Keep in mind that the modality gap can influence absolute scores: text-image pair scores may occupy a different range than text-text or image-image pair scores.</p>
<p>You can also check which modalities a reranker supports using <code>modalities</code> and <code>supports()</code>, just like with embedding models:</p>
<div class="codehilite">
<pre><span></span><code><span class="nb">print</span><span class="p">(</span><span class="n">model</span><span class="o">.</span><span class="n">modalities</span><span class="p">)</span>
<span class="c1"># [&#39;text&#39;, &#39;image&#39;, &#39;video&#39;, &#39;message&#39;]</span>

<span class="nb">print</span><span class="p">(</span><span class="n">model</span><span class="o">.</span><span class="n">supports</span><span class="p">(</span><span class="s2">&quot;image&quot;</span><span class="p">))</span>
<span class="c1"># True</span>

<span class="c1"># Check if the model supports a specific pair of modalities</span>
<span class="nb">print</span><span class="p">(</span><span class="n">model</span><span class="o">.</span><span class="n">supports</span><span class="p">((</span><span class="s2">&quot;image&quot;</span><span class="p">,</span> <span class="s2">&quot;text&quot;</span><span class="p">)))</span>
<span class="c1"># True</span>
</code></pre>
</div>
<h3>Predicting Pair Scores</h3>
<p>You can also use <code>predict()</code> to get raw relevance scores for specific pairs of inputs:</p>
<div class="codehilite">
<pre><span></span><code><span class="kn">from</span> <span class="nn">sentence_transformers</span> <span class="kn">import</span> <span class="n">CrossEncoder</span>

<span class="n">model</span> <span class="o">=</span> <span class="n">CrossEncoder</span><span class="p">(</span><span class="s2">&quot;jinaai/jina-reranker-m0&quot;</span><span class="p">,</span> <span class="n">trust_remote_code</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>

<span class="n">scores</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">predict</span><span class="p">([</span>
 <span class="p">(</span><span class="s2">&quot;A green car&quot;</span><span class="p">,</span> <span class="s2">&quot;https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/car.jpg&quot;</span><span class="p">),</span>
 <span class="p">(</span><span class="s2">&quot;A bee on a flower&quot;</span><span class="p">,</span> <span class="s2">&quot;https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg&quot;</span><span class="p">),</span>
 <span class="p">(</span><span class="s2">&quot;A green car&quot;</span><span class="p">,</span> <span class="s2">&quot;https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg&quot;</span><span class="p">),</span>
<span class="p">])</span>
<span class="nb">print</span><span class="p">(</span><span class="n">scores</span><span class="p">)</span>
<span class="c1"># [0.9389156 0.96922314 0.46063158]</span>
</code></pre>
</div>
<h3>Retrieve and Rerank</h3>
<p>A common pattern is to use an embedding model for fast initial retrieval, then refine the top results with a reranker:</p>
<div class="codehilite">
<pre><span></span><code><span class="kn">from</span> <span class="nn">sentence_transformers</span> <span class="kn">import</span> <span class="n">SentenceTransformer</span><span class="p">,</span> <span class="n">CrossEncoder</span>

<span class="c1"># Step 1: Retrieve with an embedding model</span>
<span class="n">embedder</span> <span class="o">=</span> <span class="n">SentenceTransformer</span><span class="p">(</span><span class="s2">&quot;Qwen/Qwen3-VL-Embedding-2B&quot;</span><span class="p">,</span> <span class="n">revision</span><span class="o">=</span><span class="s2">&quot;refs/pr/23&quot;</span><span class="p">)</span>

<span class="n">query</span> <span class="o">=</span> <span class="s2">&quot;revenue growth chart&quot;</span>
<span class="n">query_embedding</span> <span class="o">=</span> <span class="n">embedder</span><span class="o">.</span><span class="n">encode_query</span><span class="p">(</span><span class="n">query</span><span class="p">)</span>

<span class="c1"># Pre-compute corpus embeddings (do this once, then store them)</span>
<span class="n">document_screenshots</span> <span class="o">=</span> <span class="p">[</span>
 <span class="s2">&quot;path/to/doc1.png&quot;</span><span class="p">,</span>
 <span class="s2">&quot;path/to/doc2.png&quot;</span><span class="p">,</span>
 <span class="c1"># ... potentially millions of document screenshots</span>
<span class="p">]</span>
<span class="n">corpus_embeddings</span> <span class="o">=</span> <span class="n">embedder</span><span class="o">.</span><span class="n">encode_document</span><span class="p">(</span><span class="n">document_screenshots</span><span class="p">,</span> <span class="n">show_progress_bar</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>

<span class="c1"># Simple cosine similarity retrieval, viable as long as embeddings fit in memory</span>
<span class="n">similarities</span> <span class="o">=</span> <span class="n">embedder</span><span class="o">.</span><span class="n">similarity</span><span class="p">(</span><span class="n">query_embedding</span><span class="p">,</span> <span class="n">corpus_embeddings</span><span class="p">)</span>
<span class="n">top_k_indices</span> <span class="o">=</span> <span class="n">similarities</span><span class="o">.</span><span class="n">argsort</span><span class="p">(</span><span class="n">descending</span><span class="o">=</span><span class="kc">True</span><span class="p">)[</span><span class="mi">0</span><span class="p">][:</span><span class="mi">10</span><span class="p">]</span>

<span class="c1"># Step 2: Rerank the top-k results with a reranker model</span>
<span class="n">reranker</span> <span class="o">=</span> <span class="n">CrossEncoder</span><span class="p">(</span><span class="s2">&quot;nvidia/llama-nemotron-rerank-vl-1b-v2&quot;</span><span class="p">,</span> <span class="n">trust_remote_code</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>

<span class="n">top_k_documents</span> <span class="o">=</span> <span class="p">[</span><span class="n">document_screenshots</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">top_k_indices</span><span class="p">]</span>
<span class="n">rankings</span> <span class="o">=</span> <span class="n">reranker</span><span class="o">.</span><span class="n">rank</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">top_k_documents</span><span class="p">)</span>
<span class="k">for</span> <span class="n">rank</span> <span class="ow">in</span> <span class="n">rankings</span><span class="p">:</span>
 <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">rank</span><span class="p">[</span><span class="s1">&#39;score&#39;</span><span class="p">]</span><span class="si">:</span><span class="s2">.4f</span><span class="si">}</span><span class="se">\t</span><span class="si">{</span><span class="n">top_k_documents</span><span class="p">[</span><span class="n">rank</span><span class="p">[</span><span class="s1">&#39;corpus_id&#39;</span><span class="p">]]</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</code></pre>
</div>
<p>Since the corpus embeddings are pre-computed, the initial retrieval is fast even over millions of documents. The reranker then provides more accurate scoring over the smaller candidate set.</p>
<h2>Input Formats and Configuration</h2>
<h3>Supported Input Types</h3>
<p>Multimodal models accept a variety of input formats. Here's a summary of what you can pass to <code>model.encode()</code>:</p>
<table>
<thead>
<tr>
<th>Modality</th>
<th>Accepted Formats</th>
</tr>
</thead>
<tbody>
<tr>
<td>Text</td>
<td>- Strings</td>
</tr>
<tr>
<td>Image</td>
<td>- PIL.Image.Image objects<br />- File paths (e.g. "./photo.jpg")<br />- URLs (e.g. "https://.../image.jpg")<br />- Numpy arrays, torch tensors</td>
</tr>
<tr>
<td>Audio</td>
<td>- File paths (e.g. "./audio.wav")<br />- URLs (e.g. "https://.../audio.wav")<br />- Numpy/torch arrays<br />- Dicts with "array" and "sampling_rate" keys<br />- torchcodec.AudioDecoder instances</td>
</tr>
<tr>
<td>Video</td>
<td>- File paths (e.g. "./video.mp4")<br />- URLs (e.g. "https://.../video.mp4")<br />- Numpy/torch arrays<br />- Dicts with "array" and "video_metadata" keys<br />- torchcodec.VideoDecoder instances</td>
</tr>
<tr>
<td>Multimodal</td>
<td>- Dicts mapping modality names to values,<br />e.g. <code>{"text": "a caption", "image": "https://.../image.jpg"}</code><br />Valid keys: "text", "image", "audio", "video"</td>
</tr>
<tr>
<td>Message</td>
<td>- List of message dicts with "role" and "content" keys,<br />e.g. <code>[{"role": "user", "content": [...]}]</code></td>
</tr>
</tbody>
</table>
<h3>Checking Modality Support</h3>
<p>You can check which modalities a model supports using the <code>modalities</code> property and <code>supports()</code> method:</p>
<div class="codehilite">
<pre><span></span><code><span class="kn">from</span> <span class="nn">sentence_transformers</span> <span class="kn">import</span> <span class="n">SentenceTransformer</span>

<span class="n">model</span> <span class="o">=</span> <span class="n">SentenceTransformer</span><span class="p">(</span><span class="s2">&quot;Qwen/Qwen3-VL-Embedding-2B&quot;</span><span class="p">,</span> <span class="n">revision</span><span class="o">=</span><span class="s2">&quot;refs/pr/23&quot;</span><span class="p">)</span>

<span class="c1"># List all supported modalities</span>
<span class="nb">print</span><span class="p">(</span><span class="n">model</span><span class="o">.</span><span class="n">modalities</span><span class="p">)</span>
<span class="c1"># [&#39;text&#39;, &#39;image&#39;, &#39;video&#39;, &#39;message&#39;]</span>

<span class="c1"># Check for a specific modality</span>
<span class="nb">print</span><span class="p">(</span><span class="n">model</span><span class="o">.</span><span class="n">supports</span><span class="p">(</span><span class="s2">&quot;image&quot;</span><span class="p">))</span>
<span class="c1"># True</span>
<span class="nb">print</span><span class="p">(</span><span class="n">model</span><span class="o">.</span><span class="n">supports</span><span class="p">(</span><span class="s2">&quot;audio&quot;</span><span class="p">))</span>
<span class="c1"># False</span>
</code></pre>
</div>
<p>The "message" modality indicates that the model accepts chat-style message inputs with interleaved content. In practice, you rarely need to use this directly. When you pass strings, URLs, or multimodal dicts, the model converts them to the appropriate message format internally. Sentence Transformers supports two message formats:</p>
<ol>
<li><strong>Structured</strong> (most VLMs, e.g. Qwen3-VL): Content is a list of typed dicts, e.g. <code>[{"type": "text", "text": "..."}, {"type": "image", "image": ...}]</code></li>
<li><strong>Flat</strong> (e.g. Deepseek-V3): Content is a direct value, e.g. <code>"some text"</code></li>
</ol>
<p>The format is auto-detected from the model's chat template.</p>
<p>Since all inputs get converted into the same message format internally, you can mix input types in a single <code>encode()</code> call:</p>
<div class="codehilite">
<pre><span></span><code><span class="n">embeddings</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">encode</span><span class="p">([</span>
 <span class="c1"># A text input</span>
 <span class="s2">&quot;A green car parked in front of a yellow building&quot;</span><span class="p">,</span>
 <span class="c1"># An image input (URL)</span>
 <span class="s2">&quot;https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/car.jpg&quot;</span><span class="p">,</span>
 <span class="c1"># A combined text + image input</span>
 <span class="p">{</span>
 <span class="s2">&quot;text&quot;</span><span class="p">:</span> <span class="s2">&quot;A car in a European city&quot;</span><span class="p">,</span>
 <span class="s2">&quot;image&quot;</span><span class="p">:</span> <span class="s2">&quot;https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/car.jpg&quot;</span><span class="p">,</span>
 <span class="p">},</span>
<span class="p">])</span>
</code></pre>
</div>
<h3>Processor and Model kwargs</h3>
<p>You may want to control image resolution bounds or model precision. Use <code>processor_kwargs</code> and <code>model_kwargs</code> when loading the model:</p>
<div class="codehilite">
<pre><span></span><code><span class="n">model</span> <span class="o">=</span> <span class="n">SentenceTransformer</span><span class="p">(</span>
 <span class="s2">&quot;Qwen/Qwen3-VL-Embedding-2B&quot;</span><span class="p">,</span>
 <span class="n">model_kwargs</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;attn_implementation&quot;</span><span class="p">:</span> <span class="s2">&quot;flash_attention_2&quot;</span><span class="p">,</span> <span class="s2">&quot;torch_dtype&quot;</span><span class="p">:</span> <span class="s2">&quot;bfloat16&quot;</span><span class="p">},</span>
 <span class="n">processor_kwargs</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;min_pixels&quot;</span><span class="p">:</span> <span class="mi">28</span> <span class="o">*</span> <span class="mi">28</span><span class="p">,</span> <span class="s2">&quot;max_pixels&quot;</span><span class="p">:</span> <span class="mi">600</span> <span class="o">*</span> <span class="mi">600</span><span class="p">},</span>
 <span class="n">revision</span><span class="o">=</span><span class="s2">&quot;refs/pr/23&quot;</span><span class="p">,</span>
<span class="p">)</span>
</code></pre>
</div>
<p><code>processor_kwargs</code> controls how inputs are preprocessed (e.g., image resolution bounds). Higher <code>max_pixels</code> means higher quality but more memory and compute. These are</p>

<div class="twitter-share"><a href="https://twitter.com/intent/tweet?url=https%3A%2F%2Fwww.hardwired.dev%2F2026%2F04%2F10%2Fmultimodal-embedding-reranker-models-with-sentence-transformers%2F&#038;via=hessevalentino" class="twitter-share-button">Tweet</a></div><p>The post <a href="https://www.hardwired.dev/2026/04/10/multimodal-embedding-reranker-models-with-sentence-transformers/">Multimodal Embedding & Reranker Models with Sentence Transformers</a> first appeared on <a href="https://www.hardwired.dev">Hard Wired</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>NestJS Chapter 01 &#8211; New Project</title>
		<link>https://www.hardwired.dev/2024/06/09/nestjs-chapter-01-new-project/</link>
		
		<dc:creator><![CDATA[John Doe]]></dc:creator>
		<pubDate>Sun, 09 Jun 2024 19:09:38 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[backend]]></category>
		<category><![CDATA[crud]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[endpoint]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[nestjs]]></category>
		<category><![CDATA[nodejs]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[RESTfull]]></category>
		<category><![CDATA[typescript]]></category>
		<guid isPermaLink="false">https://www.hardwired.dev/?p=2235</guid>

					<description><![CDATA[<p>When you use an app, whether it's a web app or a desktop app, that communicates with a remote server &#62;&#62;&#62;</p>
<p>The post <a href="https://www.hardwired.dev/2024/06/09/nestjs-chapter-01-new-project/">NestJS Chapter 01 – New Project</a> first appeared on <a href="https://www.hardwired.dev">Hard Wired</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>When you use an app, whether it's a web app or a desktop app, that communicates with a remote server over the internet, you can be 99% sure there is an API server involved. API servers are the hidden part of the application where almost all the magic happens. One option for creating APIs is <a href="https://docs.nestjs.com/">NestJS</a>, and we will explore it a little bit.</p>
<p><strong>Key Benefits of NestJS:</strong></p>
<ul>
<li><strong>Scalability</strong>: NestJS is built with scalability in mind, making it easy to manage large-scale applications. Its modular architecture allows developers to split their applications into small, reusable modules.</li>
<li><strong>TypeScript Support</strong>: As a framework built on top of TypeScript, NestJS offers all the benefits of TypeScript, including type safety, improved code readability, and maintainability.</li>
<li><strong>Extensive Ecosystem</strong>: NestJS has a rich ecosystem of libraries and tools, which simplifies the development process. It integrates seamlessly with other popular libraries and frameworks like <a href="https://expressjs.com/en/guide/routing.html">Express</a>, <a href="https://fastify.dev/docs/latest/">Fastify</a>, and more.</li>
<li><strong>Ease of Use</strong>: The framework is designed to be developer-friendly, with a well-documented API and a robust CLI that helps in generating boilerplate code, thereby reducing development time.</li>
<li><strong>Dependency Injection</strong>: NestJS uses a powerful dependency injection system, which makes it easier to manage dependencies and promotes better code organization and testability.</li>
</ul>
<blockquote>
<p><strong>Disclaimer:</strong> This article is not primarily intended for people who are new to programming. It is written with the expectation of some experience in programming. To be honest, my motivation for writing this article is to compile my NestJS developer notes, and I've chosen to present them in article form. It will not explain NestJS in detail, nor its architecture. Instead, it will focus on solving specific problems I have encountered. I hope you find it useful. </p>
</blockquote>
<p>In Chapter 1, we will install NestJS and bring the API server to life.</p>
<p>Make sure you are using the latest LTS version of <a href="https://nodejs.org/en">NodeJS</a>.</p>
<p>For project creation and management, we will use <a href="https://docs.nestjs.com/cli/overview">@nestjs/cli</a>. The easiest way is to install it globally.</p>
<pre><code class="language-shell">npm i -g @nestjs/cli</code></pre>
<p>Then, in your projects folder, simply use the <code>nest</code> command to create a new project.</p>
<pre><code class="language-shell">nest new hardwired-nestjs-api-chapter-01</code></pre>
<p>You will be asked which package manager you want to use. I use <code>npm</code>.</p>
<p>When it is done, just delete the <code>.spec.ts</code> files from the <code>src</code> folder. We don't care about tests right now. A bunch of things are already set up, like <code>prettier</code>, <code>eslint</code>, and <code>TypeScript</code> configuration. Useful scripts are prepared in <code>package.json</code>.</p>
<pre><code class="language-json">&quot;scripts&quot;: {
    &quot;build&quot;: &quot;nest build&quot;,
    &quot;format&quot;: &quot;prettier --write \&quot;src/**/*.ts\&quot; \&quot;test/**/*.ts\&quot;&quot;,
    &quot;start&quot;: &quot;nest start&quot;,
    &quot;start:dev&quot;: &quot;nest start --watch&quot;,
    &quot;start:debug&quot;: &quot;nest start --debug --watch&quot;,
    &quot;start:prod&quot;: &quot;node dist/main&quot;,
    &quot;lint&quot;: &quot;eslint \&quot;{src,apps,libs,test}/**/*.ts\&quot; --fix&quot;,
    &quot;test&quot;: &quot;jest&quot;,
    &quot;test:watch&quot;: &quot;jest --watch&quot;,
    &quot;test:cov&quot;: &quot;jest --coverage&quot;,
    &quot;test:debug&quot;: &quot;node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand&quot;,
    &quot;test:e2e&quot;: &quot;jest --config ./test/jest-e2e.json&quot;
  },</code></pre>
<p>For now, we only need <code>start:dev</code> to run the development version. In the <code>src</code> folder, you can find <code>main.ts</code>, which is the entry point to our API, along with <code>app.controller.ts</code>, <code>app.module.ts</code>, and <code>app.service.ts</code>. You can find a perfect explanation of the NestJS architecture in the chapters <a href="https://docs.nestjs.com/controllers">Controllers</a>, <a href="https://docs.nestjs.com/providers">Providers</a>, and <a href="https://docs.nestjs.com/modules">Modules</a> in the NestJS documentation.</p>
<p><code>main.ts</code> is pretty simple. Just includes <code>@netjs/core</code>, <code>app.module</code> and bootstrap our application.</p>
<pre><code class="language-typescript">import { NestFactory } from &#039;@nestjs/core&#039;;
import { AppModule } from &#039;./app.module&#039;;

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}

bootstrap();</code></pre>
<p>When you run <code>npm run start:dev</code>, the API will run on port 3000, and you will be able to access it at <code>http://localhost:3000</code>.</p>
<p>Controllers are where you define your routes. In <code>app.controller.ts</code>, there is one <code>GET</code> route.</p>
<pre><code class="language-typescript">import { Controller, Get } from &#039;@nestjs/common&#039;;
import { AppService } from &#039;./app.service&#039;;

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}</code></pre>
<p>The <code>@Get</code> decorator without parameters in <code>app.controller.ts</code> indicates that you will access this route with <code>/</code>. It's the root route, and you can access it at <code>http://localhost:3000</code>. This route calls the service method <code>getHello()</code>, which returns the string <code>Hello World!</code>. Services are where your business logic resides.</p>
<pre><code class="language-typescript">import { Injectable } from &#039;@nestjs/common&#039;;

@Injectable()
export class AppService {
  getHello(): string {
    return &#039;Hello World!&#039;;
  }
}</code></pre>
<p>You can access <code>http://localhost:3000</code> in your browser, and if the development server is running, you will see <code>Hello World!</code>. However, as an API developer, you may want a better way to call your API during development. I recommend using <a href="https://insomnia.rest/">Insomnia</a>.</p>
<p>When you call <code>http://localhost:3000</code> using Insomnia, you will get the same result as in the browser. However, as you add more routes and JSON responses, you will appreciate the usefulness of Insomnia.</p>
<pre><code>Hello World!</code></pre>
<p><code>Hello World</code> is okay, but not very useful. Let's build something more meaningful.</p>
<p>First, we should discuss how to organize our routes to avoid a mess later. A good way is to organize them into <code>resources</code>. A resource can be <code>user</code>, <code>article</code>, <code>comment</code>, etc. For resource bases, we will use plurals, for example, <code>users</code>, <code>articles</code>, and <code>comments</code>. It is a good practice to follow <a href="https://restfulapi.net/">REST</a> principles when creating an API. One of my favorite articles on this topic is <a href="https://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api">Best Practices for Designing a Pragmatic RESTful API</a>.</p>
<p>Sometimes it is easier for programmers to use just <code>GET</code> and <code>POST</code> methods for all routes, but this does not adhere to <code>RESTful</code> principles. <code>RESTful</code> principles provide strategies to handle <a href="https://en.wikipedia.org/wiki/Create,_read,_update_and_delete">CRUD</a> actions. It is better to use the full potential of <code>HTTP</code> methods. For example, when we take the resource <code>user</code>:</p>
<ul>
<li><code>GET /users</code> - retrieves a list of users</li>
<li><code>GET /users/1</code> - retrieves the user with id 1</li>
<li><code>POST /users</code> - creates a new user</li>
<li><code>PUT /users/1</code> - updates the user with id 1</li>
<li><code>PATCH /users/1</code> - partially updates the user with id 1</li>
<li><code>DELETE /users/1</code> - deletes the user with id 1</li>
</ul>
<p>You can also combine resources. For instance, to get the articles for a user, one route could be <code>GET /users/1/articles</code>.</p>
<p>If you want to like an article, the API endpoint could be <code>PUT /articles/1/like</code>. You can use aliases, filtering, sorting, limiting, and pagination constructs, but this is a complex and highly opinionated field suitable for many articles. I think the best quick dive is provided in the article I mentioned earlier, written by <a href="https://www.vinaysahni.com/">Vinay Sahni</a>.</p>
<p>Earlier in the article, I said &quot;Let's build something more meaningful,&quot; but that was a lie. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /> For a quick demonstration of how to create a resource and follow methods, we will use something completely useless.</p>
<p>We will create a route <code>GET /zodiac-signs</code>. This route will return a list of zodiac signs with date ranges. I borrowed the list from <a href="https://github.com/helmasaur/zodiac-signs/blob/main/data/zodiac.json">here</a>.</p>
<p>To create a NestJS resource, we will use the <code>nest cli</code>.</p>
<pre><code class="language-shell">nest g res zodiac-signs --no-spec</code></pre>
<ul>
<li><code>nest</code> - nest command</li>
<li><code>g</code> - generate</li>
<li><code>res</code> - resource</li>
<li><code>zodiac-sign</code> - resource-name</li>
<li><code>--no-spec</code> - do not generate tests</li>
</ul>
<p>After you enter the command, you will be asked what type of transport layer you want to use. Choose REST API. The next question will be whether you would like to create CRUD entry points. I choose no; I will create them on my own.</p>
<p>When it is done, in your <code>src</code> folder, you will see a folder named <code>zodiac-signs</code>, and it will contain <code>zodiac-signs.controller.ts</code>, <code>zodiac-signs.module.ts</code>, and <code>zodiac-signs.service.ts</code>.</p>
<p>Nest CLI automatically connects your new resource/module to the app.</p>
<p>We will start with <code>zodiac-signs.service.ts</code>.</p>
<pre><code class="language-typescript">import { Injectable } from &#039;@nestjs/common&#039;;

@Injectable()
export class ZodiacSignsService {
    signs = {
        aries: {
            symbol: &#039;&#x2648;&#039;,
            dateMin: &#039;2000-03-21&#039;,
            dateMax: &#039;2000-04-20&#039;,
        },
        taurus: {
            symbol: &#039;&#x2649;&#039;,
            dateMin: &#039;2000-04-21&#039;,
            dateMax: &#039;2000-05-21&#039;,
        },
        gemini: {
            symbol: &#039;&#x264a;&#039;,
            dateMin: &#039;2000-05-22&#039;,
            dateMax: &#039;2000-06-21&#039;,
        },
        cancer: {
            symbol: &#039;&#x264b;&#039;,
            dateMin: &#039;2000-06-22&#039;,
            dateMax: &#039;2000-07-22&#039;,
        },
        leo: {
            symbol: &#039;&#x264c;&#039;,
            dateMin: &#039;2000-07-23&#039;,
            dateMax: &#039;2000-08-22&#039;,
        },
        virgo: {
            symbol: &#039;&#x264d;&#039;,
            dateMin: &#039;2000-08-23&#039;,
            dateMax: &#039;2000-09-23&#039;,
        },
        libra: {
            symbol: &#039;&#x264e;&#039;,
            dateMin: &#039;2000-09-24&#039;,
            dateMax: &#039;2000-10-23&#039;,
        },
        scorpio: {
            symbol: &#039;&#x264f;&#039;,
            dateMin: &#039;2000-10-24&#039;,
            dateMax: &#039;2000-11-22&#039;,
        },
        sagittarius: {
            symbol: &#039;&#x2650;&#039;,
            dateMin: &#039;2000-11-23&#039;,
            dateMax: &#039;2000-12-21&#039;,
        },
        capricorn: {
            symbol: &#039;&#x2651;&#039;,
            dateMin: &#039;2000-12-22&#039;,
            dateMax: &#039;2000-01-20&#039;,
        },
        aquarius: {
            symbol: &#039;&#x2652;&#039;,
            dateMin: &#039;2000-01-21&#039;,
            dateMax: &#039;2000-02-19&#039;,
        },
        pisces: {
            symbol: &#039;&#x2653;&#039;,
            dateMin: &#039;2000-02-20&#039;,
            dateMax: &#039;2000-03-20&#039;,
        },
    };

    findAll() {
        return this.signs;
    }
}</code></pre>
<p>In the <code>ZodiacSignsService</code> class, we have our logic. The list of signs is stored as a class property named <code>signs</code>. The method that returns this list is <code>findAll()</code>. It is a good practice for the route <code>GET /zodiac-signs</code> to use the service method <code>findAll</code>, and for <code>GET /zodiac-signs/:name</code> to use the service method <code>findOne</code>. This uniform naming system will help you orient yourself in a large code base.</p>
<p>Next will be <code>zodiac-signs.controller.ts</code>.</p>
<pre><code class="language-typescript">import { Controller, Get } from &#039;@nestjs/common&#039;;
import { ZodiacSignsService } from &#039;./zodiac-signs.service&#039;;

@Controller(&#039;zodiac-signs&#039;)
export class ZodiacSignsController {
  constructor(private readonly zodiacSignsService: ZodiacSignsService) {}

  @Get()
  findAll() {
    return this.zodiacSignsService.findAll();
  }
}</code></pre>
<p>We create a method <code>findAll</code> decorated with <code>@Get</code> decorator, which, without parameters, instructs the app router to point to the <code>findAll</code> method in the <code>ZodiacSignsController</code> in response to a <code>GET /zodiac-signs</code> request.</p>
<p>That's all for now. Make sure the development server is running (<code>npm run start:dev</code>). Then, you can access <code>http://localhost:3000/zodiac-signs</code>. The expected result is the same JSON as we have in <code>ZodiacSignsService</code>.</p>
<p>Okay, it's not much, but it's enough to get started. In the next chapter, we'll take a look at DTOs (Data Transfer Objects).</p>
<p>You can find project on my <a href="https://github.com/eduardtomasek/hardwired-nestjs-chapter-01-new-project">GitHub</a>.</p>
<p>Happy coding!</p>

<div class="twitter-share"><a href="https://twitter.com/intent/tweet?url=https%3A%2F%2Fwww.hardwired.dev%2F2024%2F06%2F09%2Fnestjs-chapter-01-new-project%2F&#038;via=hessevalentino" class="twitter-share-button">Tweet</a></div><p>The post <a href="https://www.hardwired.dev/2024/06/09/nestjs-chapter-01-new-project/">NestJS Chapter 01 – New Project</a> first appeared on <a href="https://www.hardwired.dev">Hard Wired</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to create TypeScript NPM package project</title>
		<link>https://www.hardwired.dev/2024/05/26/how-to-create-typescript-npm-package-project/</link>
		
		<dc:creator><![CDATA[John Doe]]></dc:creator>
		<pubDate>Sun, 26 May 2024 13:46:32 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[nodejs]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[typescript]]></category>
		<guid isPermaLink="false">https://www.hardwired.dev/?p=2200</guid>

					<description><![CDATA[<p>Sometimes you want to create your own npm package. Here is the way to set up an npm package in &#62;&#62;&#62;</p>
<p>The post <a href="https://www.hardwired.dev/2024/05/26/how-to-create-typescript-npm-package-project/">How to create TypeScript NPM package project</a> first appeared on <a href="https://www.hardwired.dev">Hard Wired</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>Sometimes you want to create your own <a href="https://www.npmjs.com/"><code>npm</code></a> package. Here is the way to set up an <code>npm</code> package in <a href="https://www.typescriptlang.org/"><code>TypeScript</code></a>.</p>
<p>In your project directory, initialize the <code>npm</code> object.</p>
<pre><code class="language-bash">npm init</code></pre>
<p>Install development dependencies.</p>
<pre><code class="language-bash">npm install --save-dev typescript ts-node</code></pre>
<p><code>ts-node</code> enables you to directly execute <code>TypeScript</code> on <a href="https://nodejs.org/en"><code>Node.js</code></a>. See more on the <a href="https://www.npmjs.com/package/ts-node">package website</a>.</p>
<p>Set up the <code>TypeScript</code> project.</p>
<pre><code class="language-bash">npx tsc --init</code></pre>
<p>In the generated <code>tsconfig.json</code>, set <code>outDir</code> to <code>dist</code>.</p>
<pre><code class="language-json">...
&quot;outDir&quot;: &quot;./dist&quot;, /* Specify an output folder for all emitted files. */
...</code></pre>
<p>In the root directory, create the <code>src</code> folder and in the folder <code>index.ts</code> which will be the entry point in your package.</p>
<pre><code class="language-bash">mkdir src
touch ./src/index.ts</code></pre>
<p>Create a <code>.gitignore</code> file.</p>
<pre><code class="language-ini">/node_modules
# Ignore test-related files
/coverage.data
/coverage/
# Build files
/dist</code></pre>
<p>Install the <a href="https://www.npmjs.com/package/tsup"><code>tsup</code></a> package. It is a <code>bundler</code> and is powered by <a href="https://github.com/evanw/esbuild"><code>esbuild</code></a>.</p>
<blockquote>
<p>In the context of JavaScript, a <strong>bundler</strong> is a tool that takes multiple JavaScript files and their dependencies and combines them into a single file or a few files, which can then be included in a web application. The main purpose of a bundler is to manage and optimize the delivery of code to the browser, enhancing performance and simplifying development.</p>
</blockquote>
<pre><code class="language-bash">
npm install --save-dev tsup</code></pre>
<p>In the root directory, create the <code>tsup.config.ts</code> file.</p>
<pre><code class="language-typescript">import { defineConfig } from &quot;tsup&quot;;
export default defineConfig({
entry: [&quot;src/index.ts&quot;],
format: [&quot;cjs&quot;, &quot;esm&quot;], // Build for commonJS and ESmodules
dts: true, // Generate declaration file (.d.ts)
splitting: false,
sourcemap: true,
clean: true,
});</code></pre>
<p>Update these properties in <code>package.json</code></p>
<pre><code class="language-json">...
&quot;main&quot;: &quot;./dist/index.js&quot;,
&quot;module&quot;: &quot;./dist/index.mjs&quot;,
&quot;types&quot;: &quot;./dist/index.d.ts&quot;,
&quot;files&quot;: [
    &quot;dist&quot;
],
&quot;scripts&quot;: {
    &quot;build&quot;: &quot;tsup&quot;
},
...</code></pre>
<p>In your <code>index.ts</code>, create a trivial function you will export in this package.</p>
<pre><code class="language-typescript">export function add(a: number, b: number): number {
  return a + b;
}</code></pre>
<p>Build your package with <code>npm run build</code>. In the <code>dist</code> directory, you will see the build of your project.</p>
<p>TADA! Now you have a base project for your <code>npm</code> package.</p>

<div class="twitter-share"><a href="https://twitter.com/intent/tweet?url=https%3A%2F%2Fwww.hardwired.dev%2F2024%2F05%2F26%2Fhow-to-create-typescript-npm-package-project%2F&#038;via=hessevalentino" class="twitter-share-button">Tweet</a></div><p>The post <a href="https://www.hardwired.dev/2024/05/26/how-to-create-typescript-npm-package-project/">How to create TypeScript NPM package project</a> first appeared on <a href="https://www.hardwired.dev">Hard Wired</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to create a new TypeScript project</title>
		<link>https://www.hardwired.dev/2024/05/25/how-to-create-a-new-typescript-project/</link>
		
		<dc:creator><![CDATA[John Doe]]></dc:creator>
		<pubDate>Sat, 25 May 2024 06:01:43 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[gts]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[nodejs]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[typescript]]></category>
		<guid isPermaLink="false">https://www.hardwired.dev/?p=2197</guid>

					<description><![CDATA[<p>TypeScript compared to JavaScript is a little bit more complex. If you do server-side JavaScript, you just call node your-script.js &#62;&#62;&#62;</p>
<p>The post <a href="https://www.hardwired.dev/2024/05/25/how-to-create-a-new-typescript-project/">How to create a new TypeScript project</a> first appeared on <a href="https://www.hardwired.dev">Hard Wired</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>TypeScript compared to JavaScript is a little bit more complex. If you do server-side JavaScript, you just call <code>node your-script.js</code> and it runs. When you want to use TypeScript, you need to install a few things and do a few steps to make your code runnable.</p>
<blockquote>
<p>Make sure you have installed the latest version of <code>nodejs</code> on your system.</p>
</blockquote>
<p>Create your project folder, change the current working directory, and install <code>typescript</code> as your development dependency.</p>
<pre><code class="language-bash">npm i -D typescript</code></pre>
<p>Initialize your <code>nodejs</code> project.</p>
<pre><code class="language-bash">npm init</code></pre>
<p>Then use <code>npx</code> to initialize a new <code>typescript</code> project.</p>
<pre><code class="language-bash">npx tsc --init</code></pre>
<p>A bunch of files should be in your project:</p>
<ul>
<li>package.json</li>
<li>package-lock.json</li>
<li>tsconfig.json</li>
</ul>
<p>Edit <code>tsconfig.json</code>, find <code>outDir</code>, and change it if you do not want compiled files in your root directory. Change it to the <code>build</code> folder.</p>
<pre><code class="language-json">...
outDir&quot;: &quot;./build&quot;,   /* Specify an output folder for all emitted files. */
...</code></pre>
<p>Now it's time to create your first TypeScript code.</p>
<p>Create a file <code>index.ts</code> and just put some random code.</p>
<pre><code class="language-typescript">async function main() {
    const i: number = 1;

    console.log(&#039;Random stuff&#039;, i);
}

main()</code></pre>
<p>Save it and then you can do a manual compilation.</p>
<pre><code class="language-bash">npx tsc</code></pre>
<p>This compiles your project and the output will be stored in the <code>build</code> folder. You will find the file <code>index.js</code> there. Do a test run with <code>node ./build/index.js</code>.</p>
<p>In the console, you should see:</p>
<pre><code class="language-bash">Random stuff 1</code></pre>
<p>You can use <code>npx tsc -w</code> to activate watch mode. When you change anything in your project, it will be recompiled automatically.</p>
<p>To make it a little bit easier, you can edit the <code>scripts</code> property in <code>package.json</code> to merge compilation and run into one command.</p>
<pre><code class="language-json">...
&quot;scripts&quot;: {
        &quot;start&quot;: &quot;npx tsc &amp;&amp; node ./build/index.js&quot;
},
...</code></pre>
<p>When you call <code>npm run start</code>, your project will be compiled and run.</p>
<p>During code development, you should use a linter to check your code using certain rules to avoid code inconsistency. An easy way is to use <code>Google TypeScript Style</code>.</p>
<p>Install <code>gts</code> as a development dependency.</p>
<pre><code class="language-bash">npm i -D gts</code></pre>
<p>Then initialize <code>gts</code> with <code>npx</code>.</p>
<pre><code class="language-bash">npx gts init</code></pre>
<p>It will ask you some questions. If your <code>typescript</code> version is higher than suggested, just say no. Then you will be asked about updating <code>tsconfig.json</code>, say yes.</p>
<p>Some big changes will be made.</p>
<p>The <code>src</code> folder will be created with an <code>index.ts</code> file in it. Remove your old <code>index.ts</code> from the root folder.</p>
<p>In <code>package.json</code>, update your start script.</p>
<pre><code class="language-json">...
&quot;start&quot;: &quot;npx tsc &amp;&amp; node ./build/src/index.js&quot;,
...</code></pre>
<blockquote>
<p>Make sure you have <code>eslint</code> support activated in your editor</p>
</blockquote>
<p>You will get an <code>index.ts</code> example file in the <code>src</code> directory. It is all wrong. If you have <code>eslint</code> support activated in your editor, it should scream at you with lots of errors.</p>
<pre><code class="language-typescript">console.log(&quot;Try npm run lint/fix!&quot;);

const longString = &#039;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer ut aliquet diam.&#039;;

const trailing = &#039;Semicolon&#039;

            const why={am:&#039;I tabbed?&#039;};

const iWish = &quot;I didn&#039;t have a trailing space...&quot;; 

const sicilian = true;;

const vizzini = (!!sicilian) ? !!!sicilian : sicilian;

const re = /foo   bar/;

export function doSomeStuff(withThis: string, andThat: string, andThose: string[]) {
    //function on one line
    if(!Boolean(andThose.length)) {return false;}
    console.log(withThis);
    console.log(andThat);
    console.dir(andThose);
    console.log(longString, trailing, why, iWish, vizzini, re);
    return;
}
// TODO: more examples</code></pre>
<p>Just run <code>npm run fix</code> to let <code>gts</code> fix your code. You will get this:</p>
<pre><code class="language-typescript">console.log(&#039;Try npm run lint/fix!&#039;);

const longString =
  &#039;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer ut aliquet diam.&#039;;

const trailing = &#039;Semicolon&#039;;

const why = {am: &#039;I tabbed?&#039;};

const iWish = &quot;I didn&#039;t have a trailing space...&quot;;

const sicilian = true;

const vizzini = sicilian ? !sicilian : sicilian;

const re = /foo {3}bar/;

export function doSomeStuff(
  withThis: string,
  andThat: string,
  andThose: string[]
) {
  //function on one line
  if (!andThose.length) {
    return false;
  }
  console.log(withThis);
  console.log(andThat);
  console.dir(andThose);
  console.log(longString, trailing, why, iWish, vizzini, re);
  return;
}
// TODO: more examples</code></pre>
<p>If it is working, you have just created your <code>typescript</code> project with a linter. It is a good thing to configure your code editor to perform <code>npm run fix</code> with every save.</p>
<p>Enjoy TypeScript coding.</p>

<div class="twitter-share"><a href="https://twitter.com/intent/tweet?url=https%3A%2F%2Fwww.hardwired.dev%2F2024%2F05%2F25%2Fhow-to-create-a-new-typescript-project%2F&#038;via=hessevalentino" class="twitter-share-button">Tweet</a></div><p>The post <a href="https://www.hardwired.dev/2024/05/25/how-to-create-a-new-typescript-project/">How to create a new TypeScript project</a> first appeared on <a href="https://www.hardwired.dev">Hard Wired</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>ESP32 RTC DS3231</title>
		<link>https://www.hardwired.dev/2023/02/28/esp32-rtc-ds3231/</link>
		
		<dc:creator><![CDATA[John Doe]]></dc:creator>
		<pubDate>Tue, 28 Feb 2023 22:17:51 +0000</pubDate>
				<category><![CDATA[Arduino]]></category>
		<category><![CDATA[Hardware]]></category>
		<category><![CDATA[IOT]]></category>
		<category><![CDATA[at24c32]]></category>
		<category><![CDATA[clock]]></category>
		<category><![CDATA[ds3231]]></category>
		<category><![CDATA[esp32]]></category>
		<category><![CDATA[iot]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[rtc]]></category>
		<category><![CDATA[time]]></category>
		<guid isPermaLink="false">https://www.hardwired.dev/?p=988</guid>

					<description><![CDATA[<p>Pokud potřebujete na ESP32 spouštět naplánované úlohy, určitě se nemůžete spoléhat na vnitřní časování. Budete potřebovat nějaký externí modul reálného &#62;&#62;&#62;</p>
<p>The post <a href="https://www.hardwired.dev/2023/02/28/esp32-rtc-ds3231/">ESP32 RTC DS3231</a> first appeared on <a href="https://www.hardwired.dev">Hard Wired</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>Pokud potřebujete na <strong>ESP32</strong> spouštět naplánované úlohy, určitě se nemůžete spoléhat na vnitřní časování. Budete potřebovat nějaký externí modul reálného času (<a href="https://sk.wikipedia.org/wiki/Hodiny_re%C3%A1lneho_%C4%8Dasu">RTC</a>), který vám na vyžádání vrátí přesný čas.</p>
<p>V bastlířské oblasti se hodně často používá <a href="https://lastminuteengineers.com/ds1307-rtc-arduino-tutorial/">DS1307</a>. Vyniká hlavně v tom, že je extrémně levný. Na <a href="https://www.aliexpress.com/item/32585872245.html">Aliexpressu</a> se dá koupit za necelých <strong>14 CZK</strong>. Cena kompenzuje určitou nepřesnost. Udává se zpoždění cca 5 minut za měsíc.</p>
<p>Sice několika násobně dražší, ale pořád směšně levný je <a href="https://lastminuteengineers.com/ds3231-rtc-arduino-tutorial/">DS3231</a>. Na <a href="https://www.aliexpress.com/item/32833136577.html">Aliexpressu</a> se dá pořídit za <strong>60 CZK</strong>.</p>
<p><img decoding="async" src="https://www.hardwired.dev/wp-content/uploads/2023/02/DS3231-AT24C32-aliexpress.jpg" alt="" /></p>
<p>U <a href="https://www.laskakit.cz/arduino-rtc-hodiny-realneho-casu-ds3231-at24c32/">Lásky</a> 128 CZK plus poštovné.</p>
<p><img decoding="async" src="https://www.hardwired.dev/wp-content/uploads/2023/02/DS3231-AT24C32-laskakit.jpg" alt="" /></p>
<p>Tento modul je daleko přesnější a obsahuje tepelně kompenzovaný krystalový oscilátor (TCXO), který odolává změnám teplot. Pro náš testovací projekt použijeme DS3231.</p>
<h1>DS3231</h1>
<p>Modul umí sledovat roky, měsíce, dny, hodiny, minuty a sekundy. Umí dokonce přestupné roky do roku 2100. Dokáže pracovat v 12 hodinovém nebo 24 hodinovém formátu. Obsahuje dva programovatelné alarmy.</p>
<p>Modul má piny pro připojení přes sběrnici I2C. Má také pin INT, který umí produkovat signál přerušení a pin SQW pro generování &quot;square wave&quot; signálu na frekvencích 1Hz, 4kHz, 8kHz nebo 32kHz.</p>
<p>Přesnost modulu je +-2 minuty za rok.</p>
<p>Modul se napájí pomocí knoflíkové baterie CR2032, LIR2032 nebo ekvivalentní o průměru 20mm. Při použití 220mAh baterie je teoretická životnost 8 let.</p>
<p>Modul obsahuje 32 bytový AT24C32 EEPROM paměťový čip s milionem zapisovacích cyklů. Neslouží pro běh hodin, může být použit pro zápis logů nebo libovolných dat.</p>
<p>Vyčerpávající popis modulu najdete na <a href="https://lastminuteengineers.com/ds3231-rtc-arduino-tutorial/">lastminuteengineers.com</a>.</p>
<h1>Zapojení</h1>
<p>Pomocí I2C připojíme k ESP modulu.</p>
<p><img decoding="async" src="https://www.hardwired.dev/wp-content/uploads/2023/02/DS3231-zapojeni.jpg" alt="" /></p>
<h1>Program</h1>
<p>Pokud nejsou hodiny nastaveny nebo mají starší čas, než je čas při kompilaci kódu, přenastaví se na aktuální čas. Po inicializaci modulu se vytvoří naplánovaná úloha pomocí modulu <code>TaskScheduler</code> a každých 10 sekund vypíše aktuální čas modulu do sériové konzole. Zbytek v komentovaném kódu.</p>
<h2>main.cpp</h2>
<pre><code class="language-cpp">/**
 * @file main.cpp
 * @author Hard Wired
 * @brief ESP32 I2C RTC test project.
 * @details
 *      Based on https://github.com/Makuna/Rtc/blob/master/examples/DS3231_Simple/DS3231_Simple.ino example.
 *      Modul tutorial https://lastminuteengineers.com/ds3231-rtc-arduino-tutorial/
 * @version 0.1
 * @date 2023-02-08
 */

#include &lt;Arduino.h&gt;

#include &lt;Wire.h&gt;
#include &lt;RtcDS3231.h&gt;
#include &lt;TaskScheduler.h&gt;

const int SECOND_IN_MILS = 1000;
const int TEN_SECONDS_IN_MILS = SECOND_IN_MILS * 10;

/**
 * @brief Vytvoření plánovače
 *
 */
Scheduler runner;

/**
 * @brief Vytvoření RTC objektu a připojení pomocí I2C sběrnice.
 *
 * @return RtcDS3231&lt;TwoWire&gt;
 */
RtcDS3231&lt;TwoWire&gt; Rtc(Wire);

/**
 * @brief Vytáhne z objektu &quot;Rtc&quot; poslední chybový stav a vypíše chybovou hlášku¨
 *        a dá vědět pomocí true/false.
 * @details see https://www.arduino.cc/reference/en/language/functions/communication/wire/endtransmission/
 *
 * @param errorTopic
 * @return true
 * @return false
 */
bool wasError(const char *errorTopic = &quot;&quot;)
{
    uint8_t error = Rtc.LastError();
    if (error != 0)
    {
        Serial.print(&quot;[&quot;);
        Serial.print(errorTopic);
        Serial.print(&quot;] WIRE communications error (&quot;);
        Serial.print(error);
        Serial.print(&quot;) : &quot;);

        switch (error)
        {
        case Rtc_Wire_Error_None:
            Serial.println(&quot;(none?!)&quot;);
            break;
        case Rtc_Wire_Error_TxBufferOverflow:
            Serial.println(&quot;transmit buffer overflow&quot;);
            break;
        case Rtc_Wire_Error_NoAddressableDevice:
            Serial.println(&quot;no device responded&quot;);
            break;
        case Rtc_Wire_Error_UnsupportedRequest:
            Serial.println(&quot;device doesn&#039;t support request&quot;);
            break;
        case Rtc_Wire_Error_Unspecific:
            Serial.println(&quot;unspecified error&quot;);
            break;
        case Rtc_Wire_Error_CommunicationTimeout:
            Serial.println(&quot;communications timed out&quot;);
            break;
        }
        return true;
    }
    return false;
}

/**
 * @brief Vypíše naformátované datum do sériové konzole.
 *
 * @param dt
 */
void printDateTime(const RtcDateTime &amp;dt)
{
    char buffer[20];

    sprintf(buffer, &quot;%d-%02d-%02d %02d:%02d:%02d&quot;, dt.Year(), dt.Month(), dt.Day(), dt.Hour(), dt.Minute(), dt.Second());

    Serial.println(buffer);
}

void printDateTimeAndTemperature()
{
    if (!Rtc.IsDateTimeValid())
    {
        if (!wasError(&quot;loop IsDateTimeValid&quot;))
        {
            // Common Causes:
            //    1) the battery on the device is low or even missing and the power line was disconnected
            Serial.println(&quot;RTC lost confidence in the DateTime!&quot;);
        }
    }

    RtcDateTime now = Rtc.GetDateTime();
    if (!wasError(&quot;loop GetDateTime&quot;))
    {
        printDateTime(now);
    }

    RtcTemperature temp = Rtc.GetTemperature();
    if (!wasError(&quot;loop GetTemperature&quot;))
    {
        temp.Print(Serial);
        // you may also get the temperature as a float and print it
        // Serial.print(temp.AsFloatDegC());
        Serial.println(&quot;C&quot;);
    }
}

/**
 * @brief Vytvoření naplánované úlohy. Poběží navždy a spustí se každých 10 sekund.
 *
 * @return Task
 */
Task PrintDateTimeAndTemperatureTask(TEN_SECONDS_IN_MILS, TASK_FOREVER, &amp;printDateTimeAndTemperature);

void setup()
{
    Serial.begin(115200);

    Serial.print(&quot;compiled: &quot;);
    // makro které expanduje datum při kompilaci kódu na &quot;mmm dd yyyy&quot; řetězec
    Serial.print(__DATE__);
    Serial.print(&#039; &#039;);
    // makro které expanduje čas při kompilaci kódu na &quot;hh:MM:ss&quot; řetězec
    Serial.println(__TIME__);

    Rtc.Begin();

#if defined(WIRE_HAS_TIMEOUT)
    Wire.setWireTimeout(3000 /* us */, true /* reset_on_timeout */);
#endif

    /**
     * @brief Vytvoří objekt RtcDateTime a nastaví ho podle času kompilace kódu.
     *
     */
    RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
    printDateTime(compiled);
    Serial.println();

    /**
     * @brief Pokud neni RTC nastaveno nastaví datum a čas.
     *
     */
    if (!Rtc.IsDateTimeValid())
    {
        if (!wasError(&quot;setup IsDateTimeValid&quot;))
        {
            // Common Causes:
            //    1) first time you ran and the device wasn&#039;t running yet
            //    2) the battery on the device is low or even missing

            Serial.println(&quot;RTC lost confidence in the DateTime!&quot;);

            // following line sets the RTC to the date &amp; time this sketch was compiled
            // it will also reset the valid flag internally unless the Rtc device is
            // having an issue

            Rtc.SetDateTime(compiled);
        }
    }

    /**
     * @brief V případě že není RTC spuštěno spustíme ho.
     *
     */
    if (!Rtc.GetIsRunning())
    {
        if (!wasError(&quot;setup GetIsRunning&quot;))
        {
            Serial.println(&quot;RTC was not actively running, starting now&quot;);
            Rtc.SetIsRunning(true);
        }
    }

    /**
     * @brief V případě, že je čas hodin starší než čas kompilace, nastaví se nový čas. Vypíše do sériové konzole informaci o nastavení RTC.
     *
     */
    RtcDateTime now = Rtc.GetDateTime();
    if (!wasError(&quot;setup GetDateTime&quot;))
    {
        if (now &lt; compiled)
        {
            Serial.println(&quot;RTC is older than compile time, updating DateTime&quot;);
            Rtc.SetDateTime(compiled);
        }
        else if (now &gt; compiled)
        {
            Serial.println(&quot;RTC is newer than compile time, this is expected&quot;);
        }
        else if (now == compiled)
        {
            Serial.println(&quot;RTC is the same as compile time, while not expected all is still fine&quot;);
        }
    }

    /*
     * Nastaví RTC modul do požadovaného stavu.
     */
    Rtc.Enable32kHzPin(false);
    wasError(&quot;setup Enable32kHzPin&quot;);
    // The INT/SQW pin on the DS3231 provides either an interrupt signal (due to alarm conditions) or a nice square wave at 1Hz, 4kHz, 8kHz, or 32kHz.
    Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeNone);
    wasError(&quot;setup SetSquareWavePin&quot;);

    /**
     * @brief Přiřazení naplánované úlohy do plánovače.
     *
     */
    runner.addTask(PrintDateTimeAndTemperatureTask);

    /**
     * @brief Povolení naplánované úlohy.
     *
     */
    PrintDateTimeAndTemperatureTask.enable();
}

void loop()
{
    runner.execute(); // spouštění plánovače
}</code></pre>
<h2>platformio.ini</h2>
<pre><code class="language-ini">[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200

lib_deps =
  makuna/RTC @ ^2.3.6
  arkhipenko/TaskScheduler @ ^3.7.0</code></pre>

<div class="twitter-share"><a href="https://twitter.com/intent/tweet?url=https%3A%2F%2Fwww.hardwired.dev%2F2023%2F02%2F28%2Fesp32-rtc-ds3231%2F&#038;via=hessevalentino" class="twitter-share-button">Tweet</a></div><p>The post <a href="https://www.hardwired.dev/2023/02/28/esp32-rtc-ds3231/">ESP32 RTC DS3231</a> first appeared on <a href="https://www.hardwired.dev">Hard Wired</a>.</p>]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
